configure first day of week for calendar and date-picker (#1952)

This commit is contained in:
Kevin Papst
2020-09-05 18:31:37 +02:00
committed by GitHub
parent ed528eb19a
commit 217960de60
30 changed files with 195 additions and 71 deletions

View File

@@ -50,4 +50,12 @@ export default class KimaiPlugin {
return this._core; return this._core;
} }
/**
* @param {string} name
* @returns {(string|number|boolean)}
*/
getConfiguration(name) {
return this.getContainer().getConfiguration().get(name);
}
} }

View File

@@ -11,14 +11,25 @@
export default class KimaiTranslation { export default class KimaiTranslation {
/**
* @param {Array<string, string>} translations
*/
constructor(translations) { constructor(translations) {
this._translations = translations; this._translations = translations;
} }
/**
* @param {string} name
* @returns {string}
*/
get(name) { get(name) {
return this._translations[name]; return this._translations[name];
} }
/**
* @param {string} name
* @returns {boolean}
*/
has(name) { has(name) {
return name in this._translations; return name in this._translations;
} }

View File

@@ -20,7 +20,7 @@ export default class KimaiAutocomplete extends KimaiPlugin {
} }
init() { init() {
this.minChars = this.getContainer().getConfiguration().get('autoComplete'); this.minChars = this.getConfiguration('autoComplete');
} }
getId() { getId() {

View File

@@ -46,7 +46,7 @@ export default class KimaiDatatable extends KimaiPlugin {
document.addEventListener(eventName, handle); document.addEventListener(eventName, handle);
} }
if (this.getContainer().getConfiguration().get('autoReloadDatatable')) { if (this.getConfiguration('autoReloadDatatable')) {
document.addEventListener('toolbar-change', handle); document.addEventListener('toolbar-change', handle);
} else { } else {
document.addEventListener('pagination-change', handle); document.addEventListener('pagination-change', handle);

View File

@@ -27,6 +27,7 @@ export default class KimaiDatePicker extends KimaiPlugin {
activateDatePicker(selector) { activateDatePicker(selector) {
const TRANSLATE = this.getContainer().getTranslation(); const TRANSLATE = this.getContainer().getTranslation();
const DATE_UTILS = this.getContainer().getPlugin('date'); const DATE_UTILS = this.getContainer().getPlugin('date');
const firstDow = this.getConfiguration('first_dow_iso');
jQuery(selector + ' ' + this.selector).each(function(index) { jQuery(selector + ' ' + this.selector).each(function(index) {
let localeFormat = jQuery(this).data('format'); let localeFormat = jQuery(this).data('format');
@@ -36,7 +37,7 @@ export default class KimaiDatePicker extends KimaiPlugin {
autoUpdateInput: false, autoUpdateInput: false,
locale: { locale: {
format: localeFormat, format: localeFormat,
firstDay: moment().startOf('week').format('d'), firstDay: firstDow,
applyLabel: TRANSLATE.get('confirm'), applyLabel: TRANSLATE.get('confirm'),
cancelLabel: TRANSLATE.get('cancel'), cancelLabel: TRANSLATE.get('cancel'),
customRangeLabel: TRANSLATE.get('customRange'), customRangeLabel: TRANSLATE.get('customRange'),

View File

@@ -27,6 +27,7 @@ export default class KimaiDateRangePicker extends KimaiPlugin {
activateDateRangePicker(selector) { activateDateRangePicker(selector) {
const TRANSLATE = this.getContainer().getTranslation(); const TRANSLATE = this.getContainer().getTranslation();
const DATE_UTILS = this.getContainer().getPlugin('date'); const DATE_UTILS = this.getContainer().getPlugin('date');
const firstDow = this.getConfiguration('first_dow_iso');
jQuery(selector + ' ' + this.selector).each(function(index) { jQuery(selector + ' ' + this.selector).each(function(index) {
let localeFormat = jQuery(this).data('format'); let localeFormat = jQuery(this).data('format');
@@ -50,7 +51,7 @@ export default class KimaiDateRangePicker extends KimaiPlugin {
locale: { locale: {
separator: separator, separator: separator,
format: localeFormat, format: localeFormat,
firstDay: moment().startOf('week').format('d'), firstDay: firstDow,
applyLabel: TRANSLATE.get('confirm'), applyLabel: TRANSLATE.get('confirm'),
cancelLabel: TRANSLATE.get('cancel'), cancelLabel: TRANSLATE.get('cancel'),
customRangeLabel: TRANSLATE.get('customRange'), customRangeLabel: TRANSLATE.get('customRange'),

View File

@@ -25,20 +25,21 @@ export default class KimaiDateTimePicker extends KimaiPlugin {
activateDateTimePicker(selector) { activateDateTimePicker(selector) {
const TRANSLATE = this.getContainer().getTranslation(); const TRANSLATE = this.getContainer().getTranslation();
const CONFIG = this.getContainer().getConfiguration();
const DATE_UTILS = this.getContainer().getPlugin('date'); const DATE_UTILS = this.getContainer().getPlugin('date');
const firstDow = this.getConfiguration('first_dow_iso');
const is24hours = this.getConfiguration('twentyFourHours');
jQuery(selector + ' ' + this.selector).each(function(index) { jQuery(selector + ' ' + this.selector).each(function(index) {
let localeFormat = jQuery(this).data('format'); let localeFormat = jQuery(this).data('format');
jQuery(this).daterangepicker({ jQuery(this).daterangepicker({
singleDatePicker: true, singleDatePicker: true,
timePicker: true, timePicker: true,
timePicker24Hour: CONFIG.get('twentyFourHours'), timePicker24Hour: is24hours,
showDropdowns: true, showDropdowns: true,
autoUpdateInput: false, autoUpdateInput: false,
locale: { locale: {
format: localeFormat, format: localeFormat,
firstDay: moment().startOf('week').format('d'), firstDay: firstDow,
applyLabel: TRANSLATE.get('confirm'), applyLabel: TRANSLATE.get('confirm'),
cancelLabel: TRANSLATE.get('cancel'), cancelLabel: TRANSLATE.get('cancel'),
customRangeLabel: TRANSLATE.get('customRange'), customRangeLabel: TRANSLATE.get('customRange'),

View File

@@ -105,7 +105,7 @@ export default class KimaiFormSelect extends KimaiPlugin {
} }
options = {...options, ...{ options = {...options, ...{
language: this.getContainer().getConfiguration().get('locale').replace('_', '-'), language: this.getConfiguration('locale').replace('_', '-'),
theme: "bootstrap", theme: "bootstrap",
matcher: matcher matcher: matcher
}}; }};

View File

@@ -29,7 +29,7 @@ export default class KimaiThemeInitializer extends KimaiPlugin {
* redirect access denied / session timeouts to login page * redirect access denied / session timeouts to login page
*/ */
registerGlobalAjaxErrorHandler() { registerGlobalAjaxErrorHandler() {
const loginUrl = this.getContainer().getConfiguration().get('login'); const loginUrl = this.getConfiguration('login');
const alert = this.getContainer().getPlugin('alert'); const alert = this.getContainer().getPlugin('alert');
const translation = this.getContainer().getTranslation().get('login.required'); const translation = this.getContainer().getTranslation().get('login.required');
jQuery(document).ajaxError(function(event, jqxhr, settings, thrownError) { jQuery(document).ajaxError(function(event, jqxhr, settings, thrownError) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,7 +5,7 @@
"build/runtime.098eaae1.js", "build/runtime.098eaae1.js",
"build/0.79dbdbb9.js", "build/0.79dbdbb9.js",
"build/1.512c747c.js", "build/1.512c747c.js",
"build/app.cafc411b.js" "build/app.27fcc913.js"
], ],
"css": [ "css": [
"build/app.554717a4.css" "build/app.554717a4.css"
@@ -53,7 +53,7 @@
"build/runtime.098eaae1.js": "sha384-xNNrNinl64G3nCUrIskgSjU0mUXXCB9lj6XCSInBTwxSKXk8uTMafnLHtdWdIGtd", "build/runtime.098eaae1.js": "sha384-xNNrNinl64G3nCUrIskgSjU0mUXXCB9lj6XCSInBTwxSKXk8uTMafnLHtdWdIGtd",
"build/0.79dbdbb9.js": "sha384-U2Ao0ORAZ8PCeDmyRsqQFET3hc7pfUBimq0PrqFdG4/s0Bdi+qBj4TJK3o70bCd5", "build/0.79dbdbb9.js": "sha384-U2Ao0ORAZ8PCeDmyRsqQFET3hc7pfUBimq0PrqFdG4/s0Bdi+qBj4TJK3o70bCd5",
"build/1.512c747c.js": "sha384-SneGUmydV7WMkwkQp+4ql0TCXq1Or/1kQeIObbiMjx9QFM0DruGsytf77g4OxrGI", "build/1.512c747c.js": "sha384-SneGUmydV7WMkwkQp+4ql0TCXq1Or/1kQeIObbiMjx9QFM0DruGsytf77g4OxrGI",
"build/app.cafc411b.js": "sha384-sc27ZMn3ySrIZOjZ6G5bkSbG5yptYP4Cck2n5p2fOid056W/QaQZN2U4vDt0EipW", "build/app.27fcc913.js": "sha384-+2s6xRVSRzLkvfRiACKfxZ1W45frODLcpIITzEJjROOjyM2EtkKMe2FE4HHZkG1m",
"build/app.554717a4.css": "sha384-dITltEp59C3NH6o/8ZcpZJgHPLx+/I5t9xDQVsbQn7YoJ0GEV82gDDqe64ebjU29", "build/app.554717a4.css": "sha384-dITltEp59C3NH6o/8ZcpZJgHPLx+/I5t9xDQVsbQn7YoJ0GEV82gDDqe64ebjU29",
"build/invoice.74279541.js": "sha384-2BXic5Sgorf2tXai6zSAN4wLY2dbg06L03/xMKW6itMcszvtnRArKzfBh6DNcF3f", "build/invoice.74279541.js": "sha384-2BXic5Sgorf2tXai6zSAN4wLY2dbg06L03/xMKW6itMcszvtnRArKzfBh6DNcF3f",
"build/invoice.13d8ef4e.css": "sha384-B6RN/wZJToSBCZk2JeLokIqWEhbh+Eb9arYbt9dM+YoC2Z6PnCeTwTqSGyexWWJh", "build/invoice.13d8ef4e.css": "sha384-B6RN/wZJToSBCZk2JeLokIqWEhbh+Eb9arYbt9dM+YoC2Z6PnCeTwTqSGyexWWJh",

View File

@@ -3,7 +3,7 @@
"build/1.512c747c.js": "build/1.512c747c.js", "build/1.512c747c.js": "build/1.512c747c.js",
"build/2.7ab75d0a.js": "build/2.7ab75d0a.js", "build/2.7ab75d0a.js": "build/2.7ab75d0a.js",
"build/app.css": "build/app.554717a4.css", "build/app.css": "build/app.554717a4.css",
"build/app.js": "build/app.cafc411b.js", "build/app.js": "build/app.27fcc913.js",
"build/calendar.css": "build/calendar.1408f57e.css", "build/calendar.css": "build/calendar.1408f57e.css",
"build/calendar.js": "build/calendar.0e49d4da.js", "build/calendar.js": "build/calendar.0e49d4da.js",
"build/chart.js": "build/chart.34d60a88.js", "build/chart.js": "build/chart.34d60a88.js",

View File

@@ -32,7 +32,7 @@ class HomepageController extends AbstractController
/** @var User $user */ /** @var User $user */
$user = $this->getUser(); $user = $this->getUser();
$userRoute = $user->getPreferenceValue('login.initial_view', InitialViewType::DEFAULT_VIEW); $userRoute = $user->getPreferenceValue('login.initial_view', InitialViewType::DEFAULT_VIEW);
$userLanguage = $user->getLocale(); $userLanguage = $user->getLanguage();
$requestLanguage = $request->getLocale(); $requestLanguage = $request->getLocale();
if (empty($requestLanguage)) { if (empty($requestLanguage)) {

View File

@@ -271,7 +271,7 @@ class ProfileController extends AbstractController
/** @var UserPreference $pref */ /** @var UserPreference $pref */
foreach ($iterator as $pref) { foreach ($iterator as $pref) {
if ($pref->isEnabled()) { if ($pref->isEnabled()) {
$sections[$pref->getSection()][] = $pref->getName(); $sections[$pref->getSection()] = $pref->getSection();
} }
} }

View File

@@ -9,6 +9,7 @@
namespace App\Entity; namespace App\Entity;
use App\Constants;
use App\Export\Annotation as Exporter; use App\Export\Annotation as Exporter;
use App\Utils\StringHelper; use App\Utils\StringHelper;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
@@ -69,7 +70,8 @@ class User extends BaseUser implements UserInterface
public const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN'; public const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
public const DEFAULT_ROLE = self::ROLE_USER; public const DEFAULT_ROLE = self::ROLE_USER;
public const DEFAULT_LANGUAGE = 'en'; public const DEFAULT_LANGUAGE = Constants::DEFAULT_LOCALE;
public const DEFAULT_FIRST_WEEKDAY = 'monday';
public const AUTH_INTERNAL = 'kimai'; public const AUTH_INTERNAL = 'kimai';
public const AUTH_LDAP = 'ldap'; public const AUTH_LDAP = 'ldap';
@@ -367,6 +369,11 @@ class User extends BaseUser implements UserInterface
$this->setPreferenceValue(UserPreference::LOCALE, $language); $this->setPreferenceValue(UserPreference::LOCALE, $language);
} }
public function getFirstDayOfWeek(): string
{
return $this->getPreferenceValue(UserPreference::FIRST_WEEKDAY, User::DEFAULT_FIRST_WEEKDAY);
}
public function setTimezone(?string $timezone) public function setTimezone(?string $timezone)
{ {
if ($timezone === null) { if ($timezone === null) {

View File

@@ -31,6 +31,7 @@ class UserPreference
public const SKIN = 'skin'; public const SKIN = 'skin';
public const LOCALE = 'language'; public const LOCALE = 'language';
public const TIMEZONE = 'timezone'; public const TIMEZONE = 'timezone';
public const FIRST_WEEKDAY = 'first_weekday';
/** /**
* @var int * @var int

View File

@@ -15,6 +15,7 @@ use App\Entity\UserPreference;
use App\Event\PrepareUserEvent; use App\Event\PrepareUserEvent;
use App\Event\UserPreferenceEvent; use App\Event\UserPreferenceEvent;
use App\Form\Type\CalendarViewType; use App\Form\Type\CalendarViewType;
use App\Form\Type\FirstWeekDayType;
use App\Form\Type\InitialViewType; use App\Form\Type\InitialViewType;
use App\Form\Type\LanguageType; use App\Form\Type\LanguageType;
use App\Form\Type\SkinType; use App\Form\Type\SkinType;
@@ -126,10 +127,17 @@ class UserPreferenceSubscriber implements EventSubscriberInterface
(new UserPreference()) (new UserPreference())
->setName(UserPreference::LOCALE) ->setName(UserPreference::LOCALE)
->setValue($this->getDefaultLanguage()) ->setValue($this->getDefaultLanguage())
->setOrder(300) ->setOrder(250)
->setSection('locale') ->setSection('locale')
->setType(LanguageType::class), ->setType(LanguageType::class),
(new UserPreference())
->setName(UserPreference::FIRST_WEEKDAY)
->setValue(User::DEFAULT_FIRST_WEEKDAY)
->setOrder(300)
->setSection('locale')
->setType(FirstWeekDayType::class),
(new UserPreference()) (new UserPreference())
->setName(UserPreference::SKIN) ->setName(UserPreference::SKIN)
->setValue($this->getDefaultTheme()) ->setValue($this->getDefaultTheme())

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Custom form field type to select the first of the week.
*/
class FirstWeekDayType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$choices = [
'Monday' => 'monday',
'Sunday' => 'sunday'
];
$resolver->setDefaults([
'multiple' => false,
'choices' => $choices,
'label' => 'first_weekday',
'translation_domain' => 'system-configuration'
]);
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return ChoiceType::class;
}
}

View File

@@ -42,7 +42,7 @@ final class UserMails implements FOSMailerInterface
public function sendConfirmationEmailMessage(UserInterface $user) public function sendConfirmationEmailMessage(UserInterface $user)
{ {
$username = $user->getUsername(); $username = $user->getUsername();
$language = 'en'; $language = User::DEFAULT_LANGUAGE;
if ($user instanceof User) { if ($user instanceof User) {
$username = $user->getDisplayName(); $username = $user->getDisplayName();
@@ -70,7 +70,7 @@ final class UserMails implements FOSMailerInterface
public function sendResettingEmailMessage(UserInterface $user) public function sendResettingEmailMessage(UserInterface $user)
{ {
$username = $user->getUsername(); $username = $user->getUsername();
$language = 'en'; $language = User::DEFAULT_LANGUAGE;
if ($user instanceof User) { if ($user instanceof User) {
$username = $user->getDisplayName(); $username = $user->getDisplayName();

View File

@@ -42,9 +42,24 @@ class Extensions extends AbstractExtension
{ {
return [ return [
new TwigFunction('class_name', [$this, 'getClassName']), new TwigFunction('class_name', [$this, 'getClassName']),
new TwigFunction('iso_day_by_name', [$this, 'getIsoDayByName']),
]; ];
} }
public function getIsoDayByName(string $weekDay): int
{
$key = array_search(
strtolower($weekDay),
['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
);
if (false === $key) {
return 1;
}
return ++$key;
}
public function color(EntityWithMetaFields $entity): ?string public function color(EntityWithMetaFields $entity): ?string
{ {
if ($entity instanceof Activity) { if ($entity instanceof Activity) {
@@ -77,7 +92,7 @@ class Extensions extends AbstractExtension
* @param object $object * @param object $object
* @return null|string * @return null|string
*/ */
public function getClassName($object) public function getClassName($object): ?string
{ {
if (!\is_object($object)) { if (!\is_object($object)) {
return null; return null;
@@ -107,11 +122,7 @@ class Extensions extends AbstractExtension
return implode(PHP_EOL, $parts); return implode(PHP_EOL, $parts);
} }
/** public function documentationLink(?string $url = ''): string
* @param string $url
* @return string
*/
public function documentationLink($url = '')
{ {
return Constants::HOMEPAGE . '/documentation/' . $url; return Constants::HOMEPAGE . '/documentation/' . $url;
} }

View File

@@ -203,6 +203,7 @@
{ {
login: '{{ path('fos_user_security_login') }}', login: '{{ path('fos_user_security_login') }}',
locale: '{{ app.request.locale }}', locale: '{{ app.request.locale }}',
first_dow_iso: {{ iso_day_by_name(app.user.firstDayOfWeek) }},
twentyFourHours: {{ 'true'|hour24('false') }}, twentyFourHours: {{ 'true'|hour24('false') }},
autoReloadDatatable: {% if theme_config('auto_reload_datatable') %}true{% else %}false{% endif %}, autoReloadDatatable: {% if theme_config('auto_reload_datatable') %}true{% else %}false{% endif %},
autoComplete: {{ theme_config('autocomplete_chars') }} autoComplete: {{ theme_config('autocomplete_chars') }}

View File

@@ -57,12 +57,45 @@
}; };
document.addEventListener('kimai.initialized', function(event) { document.addEventListener('kimai.initialized', function(event) {
var API = event.detail.kimai.getPlugin('api'); var kimai = event.detail.kimai;
var API = kimai.getPlugin('api');
$('#timesheet_calendar').fullCalendar({ $('#timesheet_calendar').fullCalendar({
defaultView: '{{ app.user.getPreferenceValue('calendar.initial_view') }}', defaultView: '{{ app.user.getPreferenceValue('calendar.initial_view') }}',
{% if not google.apiKey is null %} {% if not google.apiKey is null %}
googleCalendarApiKey: '{{ google.apiKey }}', googleCalendarApiKey: '{{ google.apiKey }}',
{% endif %} {% endif %}
header : {
left : 'prev,next today',
center: 'title',
right : 'month,agendaWeek,agendaDay'
},
eventLimit: {{ config.dayLimit }},
weekNumbers: {% if config.showWeekNumbers %}true{% else %}false{% endif %},
allDaySlot: false,
navLinks: true,
locale: kimai.getConfiguration().get('locale').replace('_', '-').toLowerCase(),
firstDay: kimai.getConfiguration().get('first_dow_iso'),
/*
// TODO calculate height properly instead of relying on the default aspectRatio
height: function() {
return 'parent';
},
*/
height: 'auto',
nowIndicator: true,
now: '{{ now|date_format('c') }}',
timezone: '{{ app.user.preferenceValue("timezone") }}',
weekends: {% if config.showWeekends %}true{% else %}false{% endif %},
businessHours: {
dow: [{{ config.businessDays|join(',') }}],
start: '{{ config.businessTimeBegin }}',
end: '{{ config.businessTimeEnd }}'
},
slotDuration: '{{ config.slotDuration }}',
slotLabelInterval: '{{ config.slotDuration }}',
minTime: '{{ config.timeframeBegin }}',
maxTime: '{{ config.timeframeEnd }}',
defaultTimedEventDuration: '00:30',
eventSources: [ eventSources: [
{ {
events: function(start, end, timezone, callback) { events: function(start, end, timezone, callback) {
@@ -107,32 +140,6 @@
} }
{% endfor %} {% endfor %}
], ],
header : {
left : 'prev,next today',
center: 'title',
right : 'month,agendaWeek,agendaDay'
},
eventLimit: {{ config.dayLimit }},
weekNumbers: {% if config.showWeekNumbers %}true{% else %}false{% endif %},
allDaySlot: false,
navLinks: true,
locale: '{{ app.request.locale|replace({'_': '-'})|lower }}',
/*
// TODO calculate height properly instead of relying on the default aspectRatio
height: function() {
return 'parent';
},
*/
height: 'auto',
nowIndicator: true,
now: '{{ now|date_format('c') }}',
timezone: '{{ app.user.preferenceValue("timezone") }}',
weekends: {% if config.showWeekends %}true{% else %}false{% endif %},
businessHours: {
dow: [{{ config.businessDays|join(',') }}],
start: '{{ config.businessTimeBegin }}',
end: '{{ config.businessTimeEnd }}'
},
eventRender: function(eventObj, $el) { eventRender: function(eventObj, $el) {
// don't show popover for google calendar // don't show popover for google calendar
if (eventObj.source.ajaxSettings !== undefined) { if (eventObj.source.ajaxSettings !== undefined) {
@@ -214,11 +221,6 @@
eventResize: changeHandler, eventResize: changeHandler,
{% endif %} {% endif %}
{% endif %} {% endif %}
slotDuration: '{{ config.slotDuration }}',
slotLabelInterval: '{{ config.slotDuration }}',
minTime: '{{ config.timeframeBegin }}',
maxTime: '{{ config.timeframeEnd }}',
defaultTimedEventDuration: '00:30'
}) })
}); });
</script> </script>

View File

@@ -2,18 +2,15 @@
{% block main %} {% block main %}
{{ form_start(form) }} {{ form_start(form) }}
{% for section, entries in sections %} {% for section in sections %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %} {% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% block box_body %} {% block box_body %}
{% for pref in form.children.preferences %} {% for pref in form.children.preferences|filter(pref => pref.vars.data.section == section)|sort((a, b) => a.vars.data.order <=> b.vars.data.order) %}
{% if pref.vars.data.name in entries %}
{{ form_row(pref) }} {{ form_row(pref) }}
{% endif %}
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}
{% endembed %} {% endembed %}
{% endfor %} {% endfor %}
{{ form_widget(form) }}
<input type="submit" value="{{ 'action.save'|trans }}" class="btn btn-primary" /> <input type="submit" value="{{ 'action.save'|trans }}" class="btn btn-primary" />
{{ form_end(form) }} {{ form_end(form) }}

View File

@@ -444,7 +444,8 @@ class ProfileControllerTest extends ControllerBaseTest
1 => ['name' => UserPreference::INTERNAL_RATE, 'value' => 19.54], 1 => ['name' => UserPreference::INTERNAL_RATE, 'value' => 19.54],
2 => ['name' => UserPreference::TIMEZONE, 'value' => 'America/Creston'], 2 => ['name' => UserPreference::TIMEZONE, 'value' => 'America/Creston'],
3 => ['name' => UserPreference::LOCALE, 'value' => 'ar'], 3 => ['name' => UserPreference::LOCALE, 'value' => 'ar'],
4 => ['name' => UserPreference::SKIN, 'value' => 'blue'], 4 => ['name' => UserPreference::FIRST_WEEKDAY, 'value' => 'sunday'],
5 => ['name' => UserPreference::SKIN, 'value' => 'blue'],
] ]
] ]
]); ]);
@@ -467,5 +468,7 @@ class ProfileControllerTest extends ControllerBaseTest
$this->assertEquals('ar', $user->getLanguage()); $this->assertEquals('ar', $user->getLanguage());
$this->assertEquals('ar', $user->getLocale()); $this->assertEquals('ar', $user->getLocale());
$this->assertEquals('blue', $user->getPreferenceValue(UserPreference::SKIN)); $this->assertEquals('blue', $user->getPreferenceValue(UserPreference::SKIN));
$this->assertEquals('sunday', $user->getPreferenceValue(UserPreference::FIRST_WEEKDAY));
$this->assertEquals('sunday', $user->getFirstDayOfWeek());
} }
} }

View File

@@ -40,7 +40,7 @@ class UserPreferenceSubscriberTest extends TestCase
self::assertSame($user, $event->getUser()); self::assertSame($user, $event->getUser());
$prefs = $sut->getDefaultPreferences($user); $prefs = $sut->getDefaultPreferences($user);
self::assertCount(11, $prefs); self::assertCount(12, $prefs);
foreach ($prefs as $pref) { foreach ($prefs as $pref) {
switch ($pref->getName()) { switch ($pref->getName()) {
@@ -49,6 +49,10 @@ class UserPreferenceSubscriberTest extends TestCase
self::assertTrue($pref->isEnabled()); self::assertTrue($pref->isEnabled());
break; break;
case UserPreference::FIRST_WEEKDAY:
self::assertEquals('monday', $pref->getValue());
break;
default: default:
self::assertTrue($pref->isEnabled()); self::assertTrue($pref->isEnabled());
} }
@@ -66,7 +70,7 @@ class UserPreferenceSubscriberTest extends TestCase
// TODO test merging values // TODO test merging values
$sut->loadUserPreferences($event); $sut->loadUserPreferences($event);
$prefs = $event->getUser()->getPreferences(); $prefs = $event->getUser()->getPreferences();
self::assertCount(11, $prefs); self::assertCount(12, $prefs);
foreach ($prefs as $pref) { foreach ($prefs as $pref) {
switch ($pref->getName()) { switch ($pref->getName()) {

View File

@@ -89,7 +89,6 @@ class DateTimeFactoryTest extends TestCase
$this->assertEquals($expected->format('Y'), $dateTime->format('Y')); $this->assertEquals($expected->format('Y'), $dateTime->format('Y'));
$this->assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); $this->assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName());
$expected = new DateTime('now', new DateTimeZone(self::TEST_TIMEZONE));
$dateTime = $sut->getStartOfWeek(); $dateTime = $sut->getStartOfWeek();
$this->assertEquals(0, $dateTime->format('H')); $this->assertEquals(0, $dateTime->format('H'));
@@ -97,8 +96,7 @@ class DateTimeFactoryTest extends TestCase
$this->assertEquals(0, $dateTime->format('s')); $this->assertEquals(0, $dateTime->format('s'));
$this->assertEquals(1, $dateTime->format('N')); $this->assertEquals(1, $dateTime->format('N'));
$this->assertEquals('Monday', $dateTime->format('l')); $this->assertEquals('Monday', $dateTime->format('l'));
$this->assertEquals($expected->format('m'), $dateTime->format('m')); // month and year can be different when the week started at the end of the month
$this->assertEquals($expected->format('Y'), $dateTime->format('Y'));
$this->assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); $this->assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName());
} }

View File

@@ -44,7 +44,7 @@ class ExtensionsTest extends TestCase
public function testGetFunctions() public function testGetFunctions()
{ {
$functions = ['class_name']; $functions = ['class_name', 'iso_day_by_name'];
$sut = $this->getSut(); $sut = $this->getSut();
$twigFunctions = $sut->getFunctions(); $twigFunctions = $sut->getFunctions();
$this->assertCount(\count($functions), $twigFunctions); $this->assertCount(\count($functions), $twigFunctions);
@@ -156,4 +156,20 @@ sdfsdf' . PHP_EOL . "\n" .
$activity->setColor('#000002'); $activity->setColor('#000002');
self::assertEquals('#000002', $sut->color($activity)); self::assertEquals('#000002', $sut->color($activity));
} }
public function testIsoDayByName()
{
$sut = $this->getSut();
self::assertEquals(1, $sut->getIsoDayByName('MoNdAy'));
self::assertEquals(2, $sut->getIsoDayByName('tuesDAY'));
self::assertEquals(3, $sut->getIsoDayByName('wednesday'));
self::assertEquals(4, $sut->getIsoDayByName('thursday'));
self::assertEquals(5, $sut->getIsoDayByName('FRIday'));
self::assertEquals(6, $sut->getIsoDayByName('saturday'));
self::assertEquals(7, $sut->getIsoDayByName('SUNDAY'));
// invalid days will return 'monday'
self::assertEquals(1, $sut->getIsoDayByName(''));
self::assertEquals(1, $sut->getIsoDayByName('sdfgsdf'));
}
} }

View File

@@ -222,6 +222,10 @@
<source>label.invoice.number_format</source> <source>label.invoice.number_format</source>
<target>Rechnungsnummer Format</target> <target>Rechnungsnummer Format</target>
</trans-unit> </trans-unit>
<trans-unit id="first_weekday">
<source>first_weekday</source>
<target>Erster Tag der Woche</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@@ -222,6 +222,10 @@
<source>label.invoice.number_format</source> <source>label.invoice.number_format</source>
<target>Invoice number format</target> <target>Invoice number format</target>
</trans-unit> </trans-unit>
<trans-unit id="first_weekday">
<source>first_weekday</source>
<target>First day of the week</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>