feat(view): Introduce year grid view (with FC multiMonthYear plugin)
Closes #159 Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
f7c5189705
commit
e4ab21072b
|
@ -31,9 +31,9 @@ return [
|
|||
['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'],
|
||||
|
|
|
@ -105,7 +105,7 @@ class SettingsController extends Controller {
|
|||
* @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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
@ -19096,6 +19108,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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -36,13 +36,14 @@
|
|||
@click.stop.prevent="toggleDatepicker"
|
||||
@mousedown.stop.prevent="doNothing"
|
||||
@mouseup.stop.prevent="doNothing">
|
||||
{{ selectedDate | formatDateRage(view, locale) }}
|
||||
{{ selectedDate | formatDateRange(view, locale) }}
|
||||
</NcButton>
|
||||
<DatePicker ref="datepicker"
|
||||
class="datepicker-button-section__datepicker"
|
||||
:date="selectedDate"
|
||||
:is-all-day="true"
|
||||
:open.sync="isDatepickerOpen"
|
||||
:type="view === 'multiMonthYear' ? 'year' : 'date'"
|
||||
@change="navigateToDate" />
|
||||
<NcButton v-shortkey="nextShortKeyConf"
|
||||
:aria-label="nextLabel"
|
||||
|
@ -64,7 +65,7 @@ import {
|
|||
modifyDate,
|
||||
} from '../../../utils/date.js'
|
||||
import { mapState } from 'vuex'
|
||||
import formatDateRage from '../../../filters/dateRangeFormat.js'
|
||||
import formatDateRange from '../../../filters/dateRangeFormat.js'
|
||||
import DatePicker from '../../Shared/DatePicker.vue'
|
||||
import ChevronLeftIcon from 'vue-material-design-icons/ChevronLeft.vue'
|
||||
import ChevronRightIcon from 'vue-material-design-icons/ChevronRight.vue'
|
||||
|
@ -79,7 +80,7 @@ export default {
|
|||
NcButton,
|
||||
},
|
||||
filters: {
|
||||
formatDateRage,
|
||||
formatDateRange,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -107,6 +108,9 @@ export default {
|
|||
case 'timeGridWeek':
|
||||
return this.$t('calendar', 'Previous week')
|
||||
|
||||
case 'multiMonthYear':
|
||||
return this.$t('calendar', 'Previous year')
|
||||
|
||||
case 'dayGridMonth':
|
||||
default:
|
||||
return this.$t('calendar', 'Previous month')
|
||||
|
@ -126,6 +130,9 @@ export default {
|
|||
case 'timeGridWeek':
|
||||
return this.$t('calendar', 'Next week')
|
||||
|
||||
case 'multiMonthYear':
|
||||
return this.$t('calendar', 'Next year')
|
||||
|
||||
case 'dayGridMonth':
|
||||
default:
|
||||
return this.$t('calendar', 'Next month')
|
||||
|
@ -158,6 +165,12 @@ export default {
|
|||
})
|
||||
break
|
||||
|
||||
case 'multiMonthYear':
|
||||
newDate = modifyDate(this.selectedDate, {
|
||||
year: factor,
|
||||
})
|
||||
break
|
||||
|
||||
case 'dayGridMonth':
|
||||
case 'listMonth':
|
||||
default: {
|
||||
|
|
|
@ -47,6 +47,7 @@ import ViewGrid from 'vue-material-design-icons/ViewGrid.vue'
|
|||
import ViewList from 'vue-material-design-icons/ViewList.vue'
|
||||
import ViewModule from 'vue-material-design-icons/ViewModule.vue'
|
||||
import ViewWeek from 'vue-material-design-icons/ViewWeek.vue'
|
||||
import ViewComfy from 'vue-material-design-icons/ViewComfy.vue'
|
||||
|
||||
export default {
|
||||
name: 'AppNavigationHeaderViewMenu',
|
||||
|
@ -55,6 +56,7 @@ export default {
|
|||
ActionButton,
|
||||
ViewDay,
|
||||
ViewGrid,
|
||||
ViewComfy,
|
||||
ViewList,
|
||||
ViewModule,
|
||||
ViewWeek,
|
||||
|
@ -73,6 +75,10 @@ export default {
|
|||
id: 'dayGridMonth',
|
||||
icon: 'ViewModule',
|
||||
label: this.$t('calendar', 'Month'),
|
||||
}, {
|
||||
id: 'multiMonthYear',
|
||||
icon: 'ViewComfy',
|
||||
label: this.$t('calendar', 'Year'),
|
||||
}, {
|
||||
id: 'listMonth',
|
||||
icon: 'ViewList',
|
||||
|
@ -87,8 +93,10 @@ export default {
|
|||
timeGridWeek_Num: [2],
|
||||
dayGridMonth: ['m'],
|
||||
dayGridMonth_Num: [3],
|
||||
multiMonthYear: ['y'],
|
||||
multiMonthYear_Num: [4],
|
||||
listMonth: ['l'],
|
||||
listMonth_Num: [4],
|
||||
listMonth_Num: [5],
|
||||
}
|
||||
},
|
||||
defaultIcon() {
|
||||
|
|
|
@ -38,6 +38,11 @@
|
|||
@click="view('dayGridMonth')">
|
||||
{{ $t('calendar', 'Month') }}
|
||||
</NcButton>
|
||||
<NcButton :type="isYearViewSelected ? 'primary' : 'secondary'"
|
||||
class="button"
|
||||
@click="view('multiMonthYear')">
|
||||
{{ $t('calendar', 'Year') }}
|
||||
</NcButton>
|
||||
<NcButton :class="isMonthListViewSelected ? 'primary' : 'secondary'"
|
||||
class="button"
|
||||
@click="view('listMonth')">
|
||||
|
@ -64,6 +69,9 @@ export default {
|
|||
isMonthViewSelected() {
|
||||
return this.selectedView === 'dayGridMonth'
|
||||
},
|
||||
isYearViewSelected() {
|
||||
return this.selectedView === 'multiMonthYear'
|
||||
},
|
||||
isMonthListViewSelected() {
|
||||
return this.selectedView === 'listMonth'
|
||||
},
|
||||
|
|
|
@ -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'),
|
||||
}],
|
||||
}, {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -40,6 +40,11 @@ const getDateFormattingConfig = () => {
|
|||
...defaultConfig,
|
||||
dayHeaderFormat: 'ddd',
|
||||
},
|
||||
multiMonthYear: {
|
||||
...defaultConfig,
|
||||
dayHeaderFormat: 'ddd',
|
||||
multiMonthMaxColumns: 4,
|
||||
},
|
||||
timeGridDay: defaultConfig,
|
||||
timeGridWeek: defaultConfig,
|
||||
listMonth: {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue