add calendar in dashboard
This commit is contained in:
parent
f180f5a531
commit
46a555a038
|
@ -1,111 +1,9 @@
|
||||||
import '../../vendor/murph/murph-core/src/core/Resources/assets/js/admin.js'
|
import '../../vendor/murph/murph-core/src/core/Resources/assets/js/admin.js'
|
||||||
|
|
||||||
const Sortable = require('sortablejs').Sortable
|
const AddressAutocomplete = require('./modules/address.js')
|
||||||
const Routing = require('../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js')
|
const FilesCollectionSorter = require('./modules/collection-sorter.js')
|
||||||
const routes = require('../../public/js/fos_js_routes.json')
|
const Calendar = require('./modules/calendar.js')
|
||||||
|
|
||||||
Routing.setRoutingData(routes)
|
|
||||||
|
|
||||||
class AddressAutocomplete {
|
|
||||||
constructor () {
|
|
||||||
this.fields = {
|
|
||||||
address: document.querySelector('#establishment_address'),
|
|
||||||
zipCode: document.querySelector('#establishment_zipCode'),
|
|
||||||
city: document.querySelector('#establishment_city')
|
|
||||||
}
|
|
||||||
|
|
||||||
this.results = []
|
|
||||||
this.timer = null
|
|
||||||
|
|
||||||
if (!this.fields.address) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const that = this
|
|
||||||
|
|
||||||
this.fields.address.addEventListener('keyup', () => {
|
|
||||||
if (that.timer) {
|
|
||||||
clearTimeout(that.timer)
|
|
||||||
}
|
|
||||||
|
|
||||||
that.timer = setTimeout(() => {
|
|
||||||
const query = that.fields.address.value
|
|
||||||
|
|
||||||
fetch(Routing.generate('admin_establishment_address', {
|
|
||||||
q: query
|
|
||||||
}))
|
|
||||||
.then(response => response.json())
|
|
||||||
.then((data) => {
|
|
||||||
that.results = data.features
|
|
||||||
that.renderResults()
|
|
||||||
})
|
|
||||||
}, 500)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
renderResults () {
|
|
||||||
const address = this.fields.address
|
|
||||||
const that = this
|
|
||||||
|
|
||||||
let wrapper = address.nextSibling
|
|
||||||
|
|
||||||
if (wrapper) {
|
|
||||||
wrapper.remove()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.results.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapper = document.createElement('div')
|
|
||||||
wrapper.classList.add('list-group', 'mt-1', 'mb-1')
|
|
||||||
|
|
||||||
for (const address of this.results) {
|
|
||||||
const item = document.createElement('div')
|
|
||||||
item.classList.add('list-group-item', 'btn', 'text-left')
|
|
||||||
item.textContent = address.properties.label
|
|
||||||
|
|
||||||
item.setAttribute('data-name', address.properties.name)
|
|
||||||
item.setAttribute('data-zipCode', address.properties.postcode)
|
|
||||||
item.setAttribute('data-city', address.properties.city)
|
|
||||||
|
|
||||||
item.addEventListener('click', (e) => {
|
|
||||||
that.fields.address.value = e.target.getAttribute('data-name')
|
|
||||||
that.fields.zipCode.value = e.target.getAttribute('data-zipCode')
|
|
||||||
that.fields.city.value = e.target.getAttribute('data-city')
|
|
||||||
|
|
||||||
wrapper.remove()
|
|
||||||
})
|
|
||||||
|
|
||||||
wrapper.appendChild(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
address.parentNode.appendChild(wrapper)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FilesCollectionSorter {
|
|
||||||
constructor () {
|
|
||||||
const collections = document.querySelectorAll('div[data-collection^="collection-files"]')
|
|
||||||
|
|
||||||
for (const collection of collections) {
|
|
||||||
return new Sortable(collection, {
|
|
||||||
handle: '*[data-collection-item]',
|
|
||||||
sort: true,
|
|
||||||
animation: 150,
|
|
||||||
fallbackTolerance: 3,
|
|
||||||
onEnd: (e) => {
|
|
||||||
const positions = collection.querySelectorAll('*[data-collection-item] input[type=hidden]')
|
|
||||||
console.log(positions);
|
|
||||||
|
|
||||||
for (let u = 0; u < positions.length; u++) {
|
|
||||||
positions[u].value = u
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new AddressAutocomplete()
|
new AddressAutocomplete()
|
||||||
new FilesCollectionSorter()
|
new FilesCollectionSorter()
|
||||||
|
new Calendar()
|
||||||
|
|
150
assets/js/components/Calendar.vue
Normal file
150
assets/js/components/Calendar.vue
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="pr-4">
|
||||||
|
<label for="projects">Période</label>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<select class="form-control mr-2" v-model="month">
|
||||||
|
<option v-for="value, key in months" v-bind:value="key">{{ value }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<select class="form-control ml-2" v-model="year">
|
||||||
|
<option v-for="value, key in years" v-bind:value="key">{{ value }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="pr-2">
|
||||||
|
<label for="projects">Intervenants</label>
|
||||||
|
<select class="form-control" v-model="selectedSpeakers" id="speakers" multiple>
|
||||||
|
<option v-for="item in speakers" v-bind:value="item.id">{{ item.name }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div>
|
||||||
|
<label for="projects">Projets</label>
|
||||||
|
<select class="form-control" v-model="selectedProjects" id="projects" multiple>
|
||||||
|
<option v-for="item in projects" v-bind:value="item.id">{{ item.label }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row" v-if="weeks.length > 0">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<table class="table table-bordered mt-3">
|
||||||
|
<Week v-for="week, key in weeks" v-bind:key="key" v-bind:week="week" />
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
table {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Routing from '../../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js'
|
||||||
|
|
||||||
|
const Week = require('./Week').default
|
||||||
|
const Choices = require('choices.js')
|
||||||
|
const chunk = require('chunk')
|
||||||
|
const axios = require('axios').default
|
||||||
|
const routes = require('../../../public/js/fos_js_routes.json')
|
||||||
|
|
||||||
|
Routing.setRoutingData(routes)
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Calendar',
|
||||||
|
components: {
|
||||||
|
Week
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
projects: [],
|
||||||
|
speakers: [],
|
||||||
|
month: new Date().getMonth() + 1,
|
||||||
|
year: new Date().getFullYear(),
|
||||||
|
years: {},
|
||||||
|
weeks: [],
|
||||||
|
months: {
|
||||||
|
1: 'Janvier',
|
||||||
|
2: 'Février',
|
||||||
|
3: 'Mars',
|
||||||
|
4: 'Avril',
|
||||||
|
5: 'Mai',
|
||||||
|
6: 'Juin',
|
||||||
|
7: 'Juillet',
|
||||||
|
8: 'Août',
|
||||||
|
9: 'Septembre',
|
||||||
|
10: 'Octobre',
|
||||||
|
11: 'Novembre',
|
||||||
|
12: 'Décembre'
|
||||||
|
},
|
||||||
|
selectedProjects: [],
|
||||||
|
selectedSpeakers: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
refresh () {
|
||||||
|
const that = this
|
||||||
|
|
||||||
|
axios.get(Routing.generate('admin_calendar_month', {
|
||||||
|
month: this.month,
|
||||||
|
year: this.year,
|
||||||
|
projects: this.selectedProjects,
|
||||||
|
speakers: this.selectedSpeakers
|
||||||
|
}))
|
||||||
|
.then((response) => {
|
||||||
|
that.weeks = chunk(response.data, 7)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
const that = this
|
||||||
|
|
||||||
|
for (let year = 2020; year <= (new Date().getFullYear() + 3); year++) {
|
||||||
|
this.years[year] = year
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.get(Routing.generate('admin_calendar_projects'))
|
||||||
|
.then((response) => {
|
||||||
|
that.projects = response.data
|
||||||
|
that.selectedProjects = response.data.map(item => item.id)
|
||||||
|
|
||||||
|
window.setTimeout(e => new Choices(document.getElementById('projects')), 500)
|
||||||
|
})
|
||||||
|
|
||||||
|
axios.get(Routing.generate('admin_calendar_speakers'))
|
||||||
|
.then((response) => {
|
||||||
|
that.speakers = response.data
|
||||||
|
that.selectedSpeakers = response.data.map(item => item.id)
|
||||||
|
|
||||||
|
window.setTimeout(e => new Choices(document.getElementById('speakers')), 500)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
year (year) {
|
||||||
|
this.refresh()
|
||||||
|
},
|
||||||
|
month (month) {
|
||||||
|
this.refresh()
|
||||||
|
},
|
||||||
|
selectedProjects (selectedProjects) {
|
||||||
|
this.refresh()
|
||||||
|
},
|
||||||
|
selectedSpeakers (selectedSpeakers) {
|
||||||
|
this.refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
95
assets/js/components/Week.vue
Normal file
95
assets/js/components/Week.vue
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<template>
|
||||||
|
<fragment>
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th v-for="item in week" v-bind:class="{'text-right': true, 'text-muted': !item.currentMonth}">
|
||||||
|
{{ item.day }}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr>
|
||||||
|
<td v-for="item in week" v-bind:class="{'bg-light': !item.currentMonth}">
|
||||||
|
<div v-for="event in item.events">
|
||||||
|
<details v-if="event.description">
|
||||||
|
<summary>
|
||||||
|
<span class="font-weight-bold">
|
||||||
|
<span class="text-muted">
|
||||||
|
[{{ event.startAt }}]
|
||||||
|
</span>
|
||||||
|
{{ event.summary }}
|
||||||
|
</span>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
<p v-html="event.description.replace(/\n/g, '<br>')" class="mt-3"></p>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<a v-bind:href="route('admin_speaker_show', {entity: speaker.id})" v-for="speaker in event.speakers" v-bind:class="['d-block mr-1 mt-1 btn btn-xs', 'btn-' + speaker.color].join(' ')">
|
||||||
|
{{ speaker.name }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a v-bind:href="route('admin_project_show', {entity: project.id})" v-for="project in event.projects" class="d-block mr-1 mt-1 btn btn-xs border btn-light">
|
||||||
|
{{ project.label }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
<div v-else>
|
||||||
|
<span class="font-weight-bold">{{ event.summary }}</span>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<a v-bind:href="route('admin_speaker_show', {entity: speaker.id})" v-for="speaker in event.speakers" v-bind:class="['d-block mr-1 mt-1 btn btn-xd', 'btn-' + speaker.color].join(' ')">
|
||||||
|
{{ speaker.name }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a v-bind:href="route('admin_project_show', {entity: project.id})" v-for="project in event.projects" class="d-block mr-1 mt-1 btn btn-xs border btn-light">
|
||||||
|
{{ project.label }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</fragment>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
td {
|
||||||
|
height: calc((100vh - 190px) / 8);
|
||||||
|
width: calc(100% / 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-xs {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 3px 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Routing from '../../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js'
|
||||||
|
import { Fragment } from 'vue-fragment'
|
||||||
|
|
||||||
|
const routes = require('../../../public/js/fos_js_routes.json')
|
||||||
|
|
||||||
|
Routing.setRoutingData(routes)
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Week',
|
||||||
|
components: {
|
||||||
|
Fragment
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
week: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
route(route, params) {
|
||||||
|
return Routing.generate(route, params)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
84
assets/js/modules/address.js
Normal file
84
assets/js/modules/address.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
const Routing = require('../../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js')
|
||||||
|
const routes = require('../../../public/js/fos_js_routes.json')
|
||||||
|
|
||||||
|
Routing.setRoutingData(routes)
|
||||||
|
|
||||||
|
class AddressAutocomplete {
|
||||||
|
constructor () {
|
||||||
|
this.fields = {
|
||||||
|
address: document.querySelector('#establishment_address'),
|
||||||
|
zipCode: document.querySelector('#establishment_zipCode'),
|
||||||
|
city: document.querySelector('#establishment_city')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.results = []
|
||||||
|
this.timer = null
|
||||||
|
|
||||||
|
if (!this.fields.address) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const that = this
|
||||||
|
|
||||||
|
this.fields.address.addEventListener('keyup', () => {
|
||||||
|
if (that.timer) {
|
||||||
|
clearTimeout(that.timer)
|
||||||
|
}
|
||||||
|
|
||||||
|
that.timer = setTimeout(() => {
|
||||||
|
const query = that.fields.address.value
|
||||||
|
|
||||||
|
fetch(Routing.generate('admin_establishment_address', {
|
||||||
|
q: query
|
||||||
|
}))
|
||||||
|
.then(response => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
that.results = data.features
|
||||||
|
that.renderResults()
|
||||||
|
})
|
||||||
|
}, 500)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
renderResults () {
|
||||||
|
const address = this.fields.address
|
||||||
|
const that = this
|
||||||
|
|
||||||
|
let wrapper = address.nextSibling
|
||||||
|
|
||||||
|
if (wrapper) {
|
||||||
|
wrapper.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.results.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper = document.createElement('div')
|
||||||
|
wrapper.classList.add('list-group', 'mt-1', 'mb-1')
|
||||||
|
|
||||||
|
for (const address of this.results) {
|
||||||
|
const item = document.createElement('div')
|
||||||
|
item.classList.add('list-group-item', 'btn', 'text-left')
|
||||||
|
item.textContent = address.properties.label
|
||||||
|
|
||||||
|
item.setAttribute('data-name', address.properties.name)
|
||||||
|
item.setAttribute('data-zipCode', address.properties.postcode)
|
||||||
|
item.setAttribute('data-city', address.properties.city)
|
||||||
|
|
||||||
|
item.addEventListener('click', (e) => {
|
||||||
|
that.fields.address.value = e.target.getAttribute('data-name')
|
||||||
|
that.fields.zipCode.value = e.target.getAttribute('data-zipCode')
|
||||||
|
that.fields.city.value = e.target.getAttribute('data-city')
|
||||||
|
|
||||||
|
wrapper.remove()
|
||||||
|
})
|
||||||
|
|
||||||
|
wrapper.appendChild(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
address.parentNode.appendChild(wrapper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AddressAutocomplete
|
17
assets/js/modules/calendar.js
Normal file
17
assets/js/modules/calendar.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
const Vue = require('vue').default
|
||||||
|
|
||||||
|
const Calendar = require('../components/Calendar').default
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
if (!document.getElementById('calendar')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vue({
|
||||||
|
el: '#calendar',
|
||||||
|
template: '<Calendar />',
|
||||||
|
components: {
|
||||||
|
Calendar
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
26
assets/js/modules/collection-sorter.js
Normal file
26
assets/js/modules/collection-sorter.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
const Sortable = require('sortablejs').Sortable
|
||||||
|
|
||||||
|
class FilesCollectionSorter {
|
||||||
|
constructor () {
|
||||||
|
const collections = document.querySelectorAll('div[data-collection^="collection-files"]')
|
||||||
|
|
||||||
|
for (const collection of collections) {
|
||||||
|
return new Sortable(collection, {
|
||||||
|
handle: '*[data-collection-item]',
|
||||||
|
sort: true,
|
||||||
|
animation: 150,
|
||||||
|
fallbackTolerance: 3,
|
||||||
|
onEnd: (e) => {
|
||||||
|
const positions = collection.querySelectorAll('*[data-collection-item] input[type=hidden]')
|
||||||
|
console.log(positions)
|
||||||
|
|
||||||
|
for (let u = 0; u < positions.length; u++) {
|
||||||
|
positions[u].value = u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = FilesCollectionSorter
|
|
@ -8,6 +8,8 @@
|
||||||
"build": "encore production --progress"
|
"build": "encore production --progress"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"murph-project": "^1"
|
"chunk": "^0.0.3",
|
||||||
|
"murph-project": "^1",
|
||||||
|
"vue-fragment": "^1.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
123
src/Controller/CalendarAdminController.php
Normal file
123
src/Controller/CalendarAdminController.php
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Repository\EventRepositoryQuery;
|
||||||
|
use App\Repository\ProjectRepositoryQuery;
|
||||||
|
use App\Repository\SpeakerRepositoryQuery;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class CalendarAdminController extends AbstractController
|
||||||
|
{
|
||||||
|
#[Route('/admin/calendar/month', name: 'admin_calendar_month', options: ['expose' => true])]
|
||||||
|
public function month(
|
||||||
|
Request $request,
|
||||||
|
SpeakerRepositoryQuery $speakerQuery,
|
||||||
|
ProjectRepositoryQuery $projectQuery,
|
||||||
|
EventRepositoryQuery $eventQuery
|
||||||
|
): Response {
|
||||||
|
$projects = $projectQuery->create()->withIds($request->query->get('projects'))->find();
|
||||||
|
$speakers = $speakerQuery->create()->withIds($request->query->get('speakers'))->find();
|
||||||
|
|
||||||
|
$month = $request->query->get('month', date('m'));
|
||||||
|
$year = $request->query->get('year', date('Y'));
|
||||||
|
|
||||||
|
$dateFrom = new \DateTime(sprintf('%d-%d-1', $year, $month));
|
||||||
|
|
||||||
|
$currentMonthFirstDayOfWeek = $dateFrom->format('N');
|
||||||
|
$nextMonthFirstDayOfWeek = date('N', $dateFrom->getTimestamp() + 3600 * 24 * $dateFrom->format('t'));
|
||||||
|
$currentMonthDays = $dateFrom->format('t');
|
||||||
|
$prevMonthDays = date('t', $dateFrom->getTimestamp() - 3600);
|
||||||
|
|
||||||
|
$days = [];
|
||||||
|
|
||||||
|
if ($currentMonthFirstDayOfWeek > 1) {
|
||||||
|
for ($day = $prevMonthDays - $currentMonthFirstDayOfWeek + 2; $day <= $prevMonthDays; ++$day) {
|
||||||
|
$days[] = [
|
||||||
|
'day' => $day,
|
||||||
|
'currentMonth' => false,
|
||||||
|
'events' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($day = 1; $day <= $currentMonthDays; ++$day) {
|
||||||
|
$events = $eventQuery->create()
|
||||||
|
->ofProjects($projects)
|
||||||
|
->ofSpeakers($speakers)
|
||||||
|
->ofMonth($month)
|
||||||
|
->ofYear($year)
|
||||||
|
->ofDay($day)
|
||||||
|
->find()
|
||||||
|
;
|
||||||
|
|
||||||
|
$events = array_map(function ($event) {
|
||||||
|
return [
|
||||||
|
'uid' => $event->getUid(),
|
||||||
|
'summary' => $event->getSummary(),
|
||||||
|
'description' => $event->getCleanedDescription(),
|
||||||
|
'startAt' => $event->getStartAt() ? $event->getStartAt()->format('H:i') : null,
|
||||||
|
'finishAt' => $event->getFinishAt() ? $event->getFinishAt()->format('H:i') : null,
|
||||||
|
'projects' => array_map(fn ($i) => [
|
||||||
|
'id' => $i->getId(),
|
||||||
|
'label' => $i->getLabel()
|
||||||
|
], $event->getProjects()->toArray()),
|
||||||
|
'speakers' => array_map(fn ($i) => [
|
||||||
|
'id' => $i->getId(),
|
||||||
|
'name' => $i->getName(),
|
||||||
|
'color' => $i->getColor(),
|
||||||
|
], $event->getSpeakers()->toArray()),
|
||||||
|
];
|
||||||
|
}, $events);
|
||||||
|
|
||||||
|
$days[] = [
|
||||||
|
'day' => $day,
|
||||||
|
'currentMonth' => true,
|
||||||
|
'events' => $events,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($nextMonthFirstDayOfWeek > 1) {
|
||||||
|
$day = 0;
|
||||||
|
|
||||||
|
for ($u = $nextMonthFirstDayOfWeek; $u <= 7; ++$u) {
|
||||||
|
$days[] = [
|
||||||
|
'day' => ++$day,
|
||||||
|
'currentMonth' => false,
|
||||||
|
'events' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json($days);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/calendar/projects', name: 'admin_calendar_projects', options: ['expose' => true])]
|
||||||
|
public function projects(ProjectRepositoryQuery $query): Response
|
||||||
|
{
|
||||||
|
$entities = array_map(function ($entity) {
|
||||||
|
return [
|
||||||
|
'id' => $entity->getId(),
|
||||||
|
'label' => $entity->getLabel(),
|
||||||
|
];
|
||||||
|
}, $query->create()->orderBy('.label')->find());
|
||||||
|
|
||||||
|
return $this->json($entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/calendar/speakers', name: 'admin_calendar_speakers', options: ['expose' => true])]
|
||||||
|
public function speakers(SpeakerRepositoryQuery $query): Response
|
||||||
|
{
|
||||||
|
$entities = array_map(function ($entity) {
|
||||||
|
return [
|
||||||
|
'id' => $entity->getId(),
|
||||||
|
'name' => $entity->getName(),
|
||||||
|
];
|
||||||
|
}, $query->create()->orderBy('.name')->find());
|
||||||
|
|
||||||
|
return $this->json($entities);
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ class ProjectAdminController extends CrudController
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/admin/project/show/{entity}", name="admin_project_show", methods={"GET"})
|
* @Route("/admin/project/show/{entity}", name="admin_project_show", methods={"GET"}, options={"expose":true})
|
||||||
*/
|
*/
|
||||||
public function show(Entity $entity): Response
|
public function show(Entity $entity): Response
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,7 +38,7 @@ class SpeakerAdminController extends CrudController
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/admin/speaker/show/{entity}", name="admin_speaker_show", methods={"GET"})
|
* @Route("/admin/speaker/show/{entity}", name="admin_speaker_show", methods={"GET"}, options={"expose":true})
|
||||||
*/
|
*/
|
||||||
public function show(Entity $entity): Response
|
public function show(Entity $entity): Response
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,20 +45,20 @@ class Event implements EntityInterface
|
||||||
*/
|
*/
|
||||||
protected $finishAt;
|
protected $finishAt;
|
||||||
|
|
||||||
/**
|
|
||||||
* @ORM\ManyToOne(targetEntity=Project::class, inversedBy="events", cascade={"persist", "remove"})
|
|
||||||
* @ORM\JoinColumn(nullable=false)
|
|
||||||
*/
|
|
||||||
protected $projects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToMany(targetEntity=Speaker::class, inversedBy="events")
|
* @ORM\ManyToMany(targetEntity=Speaker::class, inversedBy="events")
|
||||||
*/
|
*/
|
||||||
private $speakers;
|
private $speakers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToMany(targetEntity=Project::class, inversedBy="events")
|
||||||
|
*/
|
||||||
|
private $projects;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->speakers = new ArrayCollection();
|
$this->speakers = new ArrayCollection();
|
||||||
|
$this->projects = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): ?int
|
public function getId(): ?int
|
||||||
|
@ -131,18 +131,6 @@ class Event implements EntityInterface
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProjects(): ?Project
|
|
||||||
{
|
|
||||||
return $this->projects;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setProjects(?Project $projects): self
|
|
||||||
{
|
|
||||||
$this->projects = $projects;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection<int, Speaker>
|
* @return Collection<int, Speaker>
|
||||||
*/
|
*/
|
||||||
|
@ -166,4 +154,28 @@ class Event implements EntityInterface
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection<int, Project>
|
||||||
|
*/
|
||||||
|
public function getProjects(): Collection
|
||||||
|
{
|
||||||
|
return $this->projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addProject(Project $project): self
|
||||||
|
{
|
||||||
|
if (!$this->projects->contains($project)) {
|
||||||
|
$this->projects[] = $project;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeProject(Project $project): self
|
||||||
|
{
|
||||||
|
$this->projects->removeElement($project);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,9 @@ class Project implements EntityInterface
|
||||||
protected $debriefings;
|
protected $debriefings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity=Event::class, mappedBy="projects", cascade={"persist", "remove"})
|
* @ORM\ManyToMany(targetEntity=Event::class, mappedBy="projects")
|
||||||
*/
|
*/
|
||||||
protected $events;
|
private $events;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -185,20 +185,14 @@ class Project implements EntityInterface
|
||||||
*/
|
*/
|
||||||
public function getEvents(): Collection
|
public function getEvents(): Collection
|
||||||
{
|
{
|
||||||
$events = $this->events->toArray();
|
return $this->events;
|
||||||
|
|
||||||
usort($events, function($a, $b) {
|
|
||||||
return $a->getStartAt() <=> $a->getFinishAt();
|
|
||||||
});
|
|
||||||
|
|
||||||
return new ArrayCollection($events);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addEvent(Event $event): self
|
public function addEvent(Event $event): self
|
||||||
{
|
{
|
||||||
if (!$this->events->contains($event)) {
|
if (!$this->events->contains($event)) {
|
||||||
$this->events[] = $event;
|
$this->events[] = $event;
|
||||||
$event->setProjects($this);
|
$event->addProject($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -207,10 +201,7 @@ class Project implements EntityInterface
|
||||||
public function removeEvent(Event $event): self
|
public function removeEvent(Event $event): self
|
||||||
{
|
{
|
||||||
if ($this->events->removeElement($event)) {
|
if ($this->events->removeElement($event)) {
|
||||||
// set the owning side to null (unless already changed)
|
$event->removeProject($this);
|
||||||
if ($event->getProjects() === $this) {
|
|
||||||
$event->setProjects(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
@ -56,6 +56,11 @@ class Speaker implements EntityInterface, EncryptedEntityInterface
|
||||||
*/
|
*/
|
||||||
private $events;
|
private $events;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=30, nullable=true)
|
||||||
|
*/
|
||||||
|
private $color;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->interventions = new ArrayCollection();
|
$this->interventions = new ArrayCollection();
|
||||||
|
@ -192,4 +197,16 @@ class Speaker implements EntityInterface, EncryptedEntityInterface
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getColor(): ?string
|
||||||
|
{
|
||||||
|
return $this->color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setColor(?string $color): self
|
||||||
|
{
|
||||||
|
$this->color = $color;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
|
||||||
class SpeakerType extends AbstractType
|
class SpeakerType extends AbstractType
|
||||||
{
|
{
|
||||||
|
@ -14,6 +15,17 @@ class SpeakerType extends AbstractType
|
||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('name')
|
->add('name')
|
||||||
|
->add('color', ChoiceType::class, [
|
||||||
|
'required' => true,
|
||||||
|
'choices' => [
|
||||||
|
'Bleu' => 'primary',
|
||||||
|
'Gris' => 'secondary',
|
||||||
|
'Vert' => 'success',
|
||||||
|
'Rouge' => 'danger',
|
||||||
|
'Jaune' => 'warning',
|
||||||
|
'Turquoise' => 'info',
|
||||||
|
],
|
||||||
|
])
|
||||||
;
|
;
|
||||||
|
|
||||||
if ($options['edit_caldav']) {
|
if ($options['edit_caldav']) {
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
namespace App\Repository;
|
namespace App\Repository;
|
||||||
|
|
||||||
use App\Core\Repository\RepositoryQuery;
|
use App\Core\Repository\RepositoryQuery;
|
||||||
use Knp\Component\Pager\PaginatorInterface;
|
|
||||||
use App\Repository\EventRepository as Repository;
|
use App\Repository\EventRepository as Repository;
|
||||||
|
use Knp\Component\Pager\PaginatorInterface;
|
||||||
|
|
||||||
class EventRepositoryQuery extends RepositoryQuery
|
class EventRepositoryQuery extends RepositoryQuery
|
||||||
{
|
{
|
||||||
|
@ -12,4 +12,54 @@ class EventRepositoryQuery extends RepositoryQuery
|
||||||
{
|
{
|
||||||
parent::__construct($repository, 'e', $paginator);
|
parent::__construct($repository, 'e', $paginator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function ofProjects(array $projects): self
|
||||||
|
{
|
||||||
|
if (empty($projects)) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this
|
||||||
|
->innerJoin('.projects', 'p')
|
||||||
|
->andWhere('p.id IN (:projectIds)')
|
||||||
|
->setParameter('projectIds', array_map(fn ($i) => $i->getId(), $projects))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ofSpeakers(array $speakers): self
|
||||||
|
{
|
||||||
|
if (empty($speakers)) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this
|
||||||
|
->innerJoin('.speakers', 's')
|
||||||
|
->andWhere('s.id IN (:speakerIds)')
|
||||||
|
->setParameter('speakerIds', array_map(fn ($i) => $i->getId(), $speakers))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ofMonth(int $month): self
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
->andWhere('.startAt LIKE :month')
|
||||||
|
->setParameter('month', '%-'.sprintf('%02d', $month).'-% %')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ofYear(int $year): self
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
->andWhere('.startAt LIKE :year')
|
||||||
|
->setParameter('year', $year.'-%-% %')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ofDay(int $day): self
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
->andWhere('.startAt LIKE :day')
|
||||||
|
->setParameter('day', '%-%-'.sprintf('%02d', $day).' %')
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,4 +12,16 @@ class ProjectRepositoryQuery extends RepositoryQuery
|
||||||
{
|
{
|
||||||
parent::__construct($repository, 'p', $paginator);
|
parent::__construct($repository, 'p', $paginator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withIds(?array $ids)
|
||||||
|
{
|
||||||
|
if (null === $ids) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this
|
||||||
|
->andWhere('.id IN (:ids)')
|
||||||
|
->setParameter('ids', $ids)
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,18 @@ class SpeakerRepositoryQuery extends RepositoryQuery
|
||||||
parent::__construct($repository, 's', $paginator);
|
parent::__construct($repository, 's', $paginator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withIds(?array $ids)
|
||||||
|
{
|
||||||
|
if (null === $ids) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this
|
||||||
|
->andWhere('.id IN (:ids)')
|
||||||
|
->setParameter('ids', $ids)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
public function withCalendar()
|
public function withCalendar()
|
||||||
{
|
{
|
||||||
return $this
|
return $this
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
{% extends '@Core/admin/layout.html.twig' %}
|
{% extends '@Core/admin/layout.html.twig' %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="bg-light pl-5 pr-4 pt-5 pb-5">
|
<div class="row">
|
||||||
<div class="d-flex">
|
<div class="col-12">
|
||||||
<div class="mr-auto w-50">
|
<div class="p-3">
|
||||||
<h1 class="display-5">
|
<div id="calendar"></div>
|
||||||
Tableau de bord
|
|
||||||
</h1>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
46
yarn.lock
46
yarn.lock
|
@ -2246,6 +2246,11 @@ chrome-trace-event@^1.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
|
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
|
||||||
integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
|
integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
|
||||||
|
|
||||||
|
chunk@^0.0.3:
|
||||||
|
version "0.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/chunk/-/chunk-0.0.3.tgz#d4f7473e35439c543d1d209464c27839e2b51d7a"
|
||||||
|
integrity sha512-oGfwvhjGRW3Ks4GTdGoJhZWKEO1eomjOC26001R+5H0TIlP7vBCO+/XcNcPCA6ayYC7RQSq1/NsN4679Odcm5A==
|
||||||
|
|
||||||
ci-info@^1.5.0:
|
ci-info@^1.5.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
|
||||||
|
@ -2800,7 +2805,7 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "2.1.2"
|
ms "2.1.2"
|
||||||
|
|
||||||
debuglog@*, debuglog@^1.0.1:
|
debuglog@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
|
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
|
||||||
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
|
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
|
||||||
|
@ -4250,7 +4255,7 @@ import-local@^3.0.2:
|
||||||
pkg-dir "^4.2.0"
|
pkg-dir "^4.2.0"
|
||||||
resolve-cwd "^3.0.0"
|
resolve-cwd "^3.0.0"
|
||||||
|
|
||||||
imurmurhash@*, imurmurhash@^0.1.4:
|
imurmurhash@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
||||||
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
|
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
|
||||||
|
@ -4966,11 +4971,6 @@ lockfile@^1.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
signal-exit "^3.0.2"
|
signal-exit "^3.0.2"
|
||||||
|
|
||||||
lodash._baseindexof@*:
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
|
|
||||||
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=
|
|
||||||
|
|
||||||
lodash._baseuniq@~4.6.0:
|
lodash._baseuniq@~4.6.0:
|
||||||
version "4.6.0"
|
version "4.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
|
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
|
||||||
|
@ -4979,33 +4979,11 @@ lodash._baseuniq@~4.6.0:
|
||||||
lodash._createset "~4.0.0"
|
lodash._createset "~4.0.0"
|
||||||
lodash._root "~3.0.0"
|
lodash._root "~3.0.0"
|
||||||
|
|
||||||
lodash._bindcallback@*:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
|
|
||||||
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
|
|
||||||
|
|
||||||
lodash._cacheindexof@*:
|
|
||||||
version "3.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
|
|
||||||
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=
|
|
||||||
|
|
||||||
lodash._createcache@*:
|
|
||||||
version "3.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
|
|
||||||
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
|
|
||||||
dependencies:
|
|
||||||
lodash._getnative "^3.0.0"
|
|
||||||
|
|
||||||
lodash._createset@~4.0.0:
|
lodash._createset@~4.0.0:
|
||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
|
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
|
||||||
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
|
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
|
||||||
|
|
||||||
lodash._getnative@*, lodash._getnative@^3.0.0:
|
|
||||||
version "3.9.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
|
|
||||||
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
|
|
||||||
|
|
||||||
lodash._root@~3.0.0:
|
lodash._root@~3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
|
resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
|
||||||
|
@ -5036,11 +5014,6 @@ lodash.merge@^4.6.2:
|
||||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||||
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
||||||
|
|
||||||
lodash.restparam@*:
|
|
||||||
version "3.6.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
|
|
||||||
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
|
|
||||||
|
|
||||||
lodash.truncate@^4.4.2:
|
lodash.truncate@^4.4.2:
|
||||||
version "4.4.2"
|
version "4.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
|
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
|
||||||
|
@ -8024,6 +7997,11 @@ vue-eslint-parser@^7.10.0:
|
||||||
lodash "^4.17.21"
|
lodash "^4.17.21"
|
||||||
semver "^6.3.0"
|
semver "^6.3.0"
|
||||||
|
|
||||||
|
vue-fragment@^1.5.2:
|
||||||
|
version "1.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-fragment/-/vue-fragment-1.5.2.tgz#310017170c564c4aad95da14c185c92c6784fd3c"
|
||||||
|
integrity sha512-KEW0gkeNOLJjtXN4jqJhTazez5jtrwimHkE5Few/VxblH4F9EcvJiEsahrV5kg5uKd5U8du4ORKS6QjGE0piYA==
|
||||||
|
|
||||||
vue-hot-reload-api@^2.3.0:
|
vue-hot-reload-api@^2.3.0:
|
||||||
version "2.3.4"
|
version "2.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
|
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
|
||||||
|
|
Loading…
Reference in a new issue