diff --git a/appinfo/routes.php b/appinfo/routes.php
index 6a494159de..533b426e4c 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -31,9 +31,9 @@
['name' => 'view#index', 'url' => '/new/{isAllDay}/{dtStart}/{dtEnd}', 'verb' => 'GET', 'postfix' => 'direct.new.timerange'],
['name' => 'view#index', 'url' => '/edit/{objectId}', 'verb' => 'GET', 'postfix' => 'direct.edit'],
['name' => 'view#index', 'url' => '/edit/{objectId}/{recurrenceId}', 'verb' => 'GET', 'postfix' => 'direct.edit.recurrenceId'],
- ['name' => 'view#index', 'url' => '/{view}/{timeRange}', 'verb' => 'GET', 'requirements' => ['view' => 'timeGridDay|timeGridWeek|dayGridMonth|listMonth'], 'postfix' => 'view.timerange'],
- ['name' => 'view#index', 'url' => '/{view}/{timeRange}/new/{mode}/{isAllDay}/{dtStart}/{dtEnd}', 'verb' => 'GET', 'requirements' => ['view' => 'timeGridDay|timeGridWeek|dayGridMonth|listMonth'], 'postfix' => 'view.timerange.new'],
- ['name' => 'view#index', 'url' => '/{view}/{timeRange}/edit/{mode}/{objectId}/{recurrenceId}', 'verb' => 'GET', 'requirements' => ['view' => 'timeGridDay|timeGridWeek|dayGridMonth|listMonth'], 'postfix' => 'view.timerange.edit'],
+ ['name' => 'view#index', 'url' => '/{view}/{timeRange}', 'verb' => 'GET', 'requirements' => ['view' => 'timeGridDay|timeGridWeek|dayGridMonth|multiMonthYear|listMonth'], 'postfix' => 'view.timerange'],
+ ['name' => 'view#index', 'url' => '/{view}/{timeRange}/new/{mode}/{isAllDay}/{dtStart}/{dtEnd}', 'verb' => 'GET', 'requirements' => ['view' => 'timeGridDay|timeGridWeek|dayGridMonth|multiMonthYear|listMonth'], 'postfix' => 'view.timerange.new'],
+ ['name' => 'view#index', 'url' => '/{view}/{timeRange}/edit/{mode}/{objectId}/{recurrenceId}', 'verb' => 'GET', 'requirements' => ['view' => 'timeGridDay|timeGridWeek|dayGridMonth|multiMonthYear|listMonth'], 'postfix' => 'view.timerange.edit'],
['name' => 'view#getCalendarDotSvg', 'url' => '/public/getCalendarDotSvg/{color}.svg', 'verb' => 'GET'],
// Appointments
['name' => 'appointment#index', 'url' => '/appointments/{userId}', 'verb' => 'GET'],
diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php
index 81a78b77ee..fe30d548d2 100644
--- a/lib/Controller/SettingsController.php
+++ b/lib/Controller/SettingsController.php
@@ -105,7 +105,7 @@ public function setConfig(string $key,
* @return JSONResponse
*/
private function setView(string $view):JSONResponse {
- if (!\in_array($view, ['timeGridDay', 'timeGridWeek', 'dayGridMonth', 'listMonth'])) {
+ if (!\in_array($view, ['timeGridDay', 'timeGridWeek', 'dayGridMonth', 'multiMonthYear', 'listMonth'])) {
return new JSONResponse([], Http::STATUS_UNPROCESSABLE_ENTITY);
}
diff --git a/package-lock.json b/package-lock.json
index 8339e30fbe..975a5112bb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
"@fullcalendar/daygrid": "6.1.8",
"@fullcalendar/interaction": "6.1.8",
"@fullcalendar/list": "6.1.8",
+ "@fullcalendar/multimonth": "6.1.8",
"@fullcalendar/resource": "6.1.8",
"@fullcalendar/resource-timeline": "6.1.8",
"@fullcalendar/timegrid": "6.1.8",
@@ -2074,6 +2075,17 @@
"@fullcalendar/core": "~6.1.8"
}
},
+ "node_modules/@fullcalendar/multimonth": {
+ "version": "6.1.8",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/multimonth/-/multimonth-6.1.8.tgz",
+ "integrity": "sha512-3F0NlncQTfeE9x5ICxh/M9DaSdY6XjgM1NazY8k+d6ukd1jthHI7vs6j7tXJI9eGUKs3DNNEyzN/LoP06SIyKw==",
+ "dependencies": {
+ "@fullcalendar/daygrid": "~6.1.8"
+ },
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.8"
+ }
+ },
"node_modules/@fullcalendar/premium-common": {
"version": "6.1.8",
"resolved": "https://registry.npmjs.org/@fullcalendar/premium-common/-/premium-common-6.1.8.tgz",
@@ -19105,6 +19117,14 @@
"integrity": "sha512-10N0T/vCtId1cE3JGLpnbAivWVnaWCCkVO7wmbsyr5Y+I939kr/zq4BUNwBoP/xSFVVxx59FETh3iyA+MkV8Fw==",
"requires": {}
},
+ "@fullcalendar/multimonth": {
+ "version": "6.1.8",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/multimonth/-/multimonth-6.1.8.tgz",
+ "integrity": "sha512-3F0NlncQTfeE9x5ICxh/M9DaSdY6XjgM1NazY8k+d6ukd1jthHI7vs6j7tXJI9eGUKs3DNNEyzN/LoP06SIyKw==",
+ "requires": {
+ "@fullcalendar/daygrid": "~6.1.8"
+ }
+ },
"@fullcalendar/premium-common": {
"version": "6.1.8",
"resolved": "https://registry.npmjs.org/@fullcalendar/premium-common/-/premium-common-6.1.8.tgz",
diff --git a/package.json b/package.json
index 352f563bd4..16228060be 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"@fullcalendar/daygrid": "6.1.8",
"@fullcalendar/interaction": "6.1.8",
"@fullcalendar/list": "6.1.8",
+ "@fullcalendar/multimonth": "6.1.8",
"@fullcalendar/resource": "6.1.8",
"@fullcalendar/resource-timeline": "6.1.8",
"@fullcalendar/timegrid": "6.1.8",
diff --git a/src/components/AppNavigation/AppNavigationHeader/AppNavigationHeaderDatePicker.vue b/src/components/AppNavigation/AppNavigationHeader/AppNavigationHeaderDatePicker.vue
index 195fbc8979..5cceaf6508 100644
--- a/src/components/AppNavigation/AppNavigationHeader/AppNavigationHeaderDatePicker.vue
+++ b/src/components/AppNavigation/AppNavigationHeader/AppNavigationHeaderDatePicker.vue
@@ -36,13 +36,14 @@
@click.stop.prevent="toggleDatepicker"
@mousedown.stop.prevent="doNothing"
@mouseup.stop.prevent="doNothing">
- {{ selectedDate | formatDateRage(view, locale) }}
+ {{ selectedDate | formatDateRange(view, locale) }}
{{ $t('calendar', 'Month') }}
+
+ {{ $t('calendar', 'Year') }}
+
@@ -64,6 +69,9 @@ export default {
isMonthViewSelected() {
return this.selectedView === 'dayGridMonth'
},
+ isYearViewSelected() {
+ return this.selectedView === 'multiMonthYear'
+ },
isMonthListViewSelected() {
return this.selectedView === 'listMonth'
},
diff --git a/src/components/AppNavigation/Settings/ShortcutOverview.vue b/src/components/AppNavigation/Settings/ShortcutOverview.vue
index 473411ac18..3124064e9f 100644
--- a/src/components/AppNavigation/Settings/ShortcutOverview.vue
+++ b/src/components/AppNavigation/Settings/ShortcutOverview.vue
@@ -91,7 +91,10 @@ export default {
keys: [['3'], ['m']],
label: t('calendar', 'Month view'),
}, {
- keys: [['4'], ['l']],
+ keys: [['4'], ['y']],
+ label: t('calendar', 'Year view'),
+ }, {
+ keys: [['5'], ['l']],
label: t('calendar', 'List view'),
}],
}, {
diff --git a/src/components/CalendarGrid.vue b/src/components/CalendarGrid.vue
index 8d1c519211..fe632d4ba6 100644
--- a/src/components/CalendarGrid.vue
+++ b/src/components/CalendarGrid.vue
@@ -33,6 +33,7 @@ import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin from '@fullcalendar/interaction'
import listPlugin from '@fullcalendar/list'
import timeGridPlugin from '@fullcalendar/timegrid'
+import multiMonthPlugin from '@fullcalendar/multimonth'
// Import event sources
import eventSource from '../fullcalendar/eventSources/eventSource.js'
@@ -164,6 +165,7 @@ export default {
interactionPlugin,
listPlugin,
timeGridPlugin,
+ multiMonthPlugin,
]
},
isEditable() {
diff --git a/src/components/Shared/DatePicker.vue b/src/components/Shared/DatePicker.vue
index 3f8c2ff4df..873573dbda 100644
--- a/src/components/Shared/DatePicker.vue
+++ b/src/components/Shared/DatePicker.vue
@@ -26,7 +26,7 @@
:format="'YYYY-MM-DD HH:mm'"
:formatter="formatter"
:value="date"
- :type="type"
+ :type="actualType"
:clearable="false"
:minute-step="5"
:disabled-date="disabledDate"
@@ -142,6 +142,10 @@ export default {
type: Boolean,
default: false,
},
+ type: {
+ type: String,
+ default: 'datetime',
+ },
},
data() {
return {
@@ -187,12 +191,12 @@ export default {
*
* @return {string}
*/
- type() {
- if (this.isAllDay) {
+ actualType() {
+ if (this.type === 'datetime' && this.isAllDay) {
return 'date'
}
- return 'datetime'
+ return this.type
},
/**
* The earliest date a user is allowed to pick in the timezone
diff --git a/src/filters/dateRangeFormat.js b/src/filters/dateRangeFormat.js
index 1b996f8b7a..410d996cda 100644
--- a/src/filters/dateRangeFormat.js
+++ b/src/filters/dateRangeFormat.js
@@ -41,6 +41,9 @@ export default (value, view, locale) => {
year: moment(value).locale(locale).weekYear(),
})
+ case 'multiMonthYear':
+ return moment(value).locale(locale).format('YYYY')
+
case 'dayGridMonth':
case 'listMonth':
default:
diff --git a/src/fullcalendar/localization/dateFormattingConfig.js b/src/fullcalendar/localization/dateFormattingConfig.js
index c7765cdfc7..812ba0b4b7 100644
--- a/src/fullcalendar/localization/dateFormattingConfig.js
+++ b/src/fullcalendar/localization/dateFormattingConfig.js
@@ -40,6 +40,11 @@ const getDateFormattingConfig = () => {
...defaultConfig,
dayHeaderFormat: 'ddd',
},
+ multiMonthYear: {
+ ...defaultConfig,
+ dayHeaderFormat: 'ddd',
+ multiMonthMaxColumns: 4,
+ },
timeGridDay: defaultConfig,
timeGridWeek: defaultConfig,
listMonth: {
diff --git a/src/utils/date.js b/src/utils/date.js
index 4b0c3f9cf3..30ed9b45d0 100644
--- a/src/utils/date.js
+++ b/src/utils/date.js
@@ -120,13 +120,15 @@ export function getDateFromDateTimeValue(dateTimeValue) {
* @param {number} data.day Number of days to add
* @param {number} data.week Number of weeks to add
* @param {number} data.month Number of months to add
+ * @param data.year
* @return {Date}
*/
-export function modifyDate(date, { day = 0, week = 0, month = 0 }) {
+export function modifyDate(date, { day = 0, week = 0, month = 0, year = 0 }) {
date = new Date(date.getTime())
date.setDate(date.getDate() + day)
date.setDate(date.getDate() + week * 7)
date.setMonth(date.getMonth() + month)
+ date.setFullYear(date.getFullYear() + year)
return date
}