1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-19 13:54:25 +01:00

Ability to show the scheduled events in the admin calendar

This commit is contained in:
Sylvain 2019-11-25 14:49:39 +01:00
parent 563de29b9d
commit 68b17cbe9a
15 changed files with 78 additions and 14 deletions

View File

@ -4,6 +4,7 @@
- An administrator can delete a member
- An event can be cancelled, if reservation cancellation is enabled
- Ability to configure the duration of a reservation slot. Previously, only 60 minutes slots were allowed
- Ability to show the scheduled events in the admin calendar
- Display indications on required fields in new administrator form
- Configuration of phone number in members registration forms: can be required or optional, depending on `PHONE_REQUIRED` configuration
- Improved user experience in defining slots in the calendar management
@ -16,6 +17,7 @@
- Fix a security issue: updated angular to 1.7.9 to fix [CVE-2019-10768](https://github.com/advisories/GHSA-89mq-4x47-5v83)
- [TODO DEPLOY] add the `SLOT_DURATION` environment variable (see [doc/environment.md](doc/environment.md#SLOT_DURATION) for configuration details)
- [TODO DEPLOY] add the `PHONE_REQUIRED` environment variable (see [doc/environment.md](doc/environment.md#PHONE_REQUIRED) for configuration details)
- [TODO DEPLOY] add the `EVENTS_IN_CALENDAR` environment variable (see [doc/environment.md](doc/environment.md#EVENTS_IN_CALENDAR) for configuration details)
- [TODO DEPLOY] -> (only dev) `bundle install && yarn install`
- [TODO DEPLOY] `rake db:migrate`

View File

@ -343,7 +343,9 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
* @see http://fullcalendar.io/docs/event_rendering/eventRender/
*/
var eventRenderCb = function (event, element) {
element.find('.fc-content').prepend('<span class="remove-event">x&nbsp;</span>');
if (event.available_type !== 'event') {
element.find('.fc-content').prepend('<span class="remove-event">x&nbsp;</span>');
}
if (event.tags.length > 0) {
let html = '';
for (let tag of Array.from(event.tags)) {

View File

@ -15,6 +15,7 @@
.border-machine { border-color: $beige !important; }
.border-space { border-color: $cyan !important; }
.border-formation { border-color: $violet !important; }
.border-event { border-color: $japonica !important; }
.bg-black-light { background-color: #424242 !important; }

View File

@ -101,6 +101,21 @@
}
}
.display-h {
display: flex;
flex-direction: row;
justify-content: space-evenly;
padding: 0;
}
.display-v {
display: flex;
flex-direction: column;
justify-content: space-around;
align-self: baseline;
height: inherit;
}
body.container{
padding: 0;

View File

@ -12,10 +12,15 @@
</div>
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md">
<section class="heading-actions wrapper" ng-class="{'p-s': !fablabWithoutSpaces}">
<span class="calendar-legend text-sm border-formation" ng-class="{'m-t-sm': fablabWithoutSpaces}" translate>{{ 'admin_calendar.trainings' }}</span><br>
<span class="calendar-legend text-sm border-machine" translate>{{ 'admin_calendar.machines' }}</span><br>
<span class="calendar-legend text-sm border-space" ng-hide="fablabWithoutSpaces" translate>{{ 'admin_calendar.spaces' }}</span>
<section class="heading-actions wrapper display-h" ng-class="{'p-s': !fablabWithoutSpaces}">
<div class="display-v">
<span class="calendar-legend text-sm border-formation" ng-class="{'m-t-sm': fablabWithoutSpaces}" translate>{{ 'admin_calendar.trainings' }}</span><br>
<span class="calendar-legend text-sm border-machine" translate>{{ 'admin_calendar.machines' }}</span><br>
</div>
<div class="display-v">
<span class="calendar-legend text-sm border-space" ng-hide="fablabWithoutSpaces" translate>{{ 'admin_calendar.spaces' }}</span>
<span class="calendar-legend text-sm border-event" ng-hide="fablabWithoutSpaces" translate>{{ 'admin_calendar.events' }}</span>
</div>
</section>
</div>
@ -43,7 +48,7 @@
<iframe name="export-frame" height="0" width="0" class="none"></iframe>
</div>
<div class="widget panel b-a m m-t-lg" ng-if="availability">
<div class="widget panel b-a m m-t-lg" ng-if="availability" ng-hide="availability.available_type == 'event'">
<div class="panel-heading b-b small">
<h3 translate>{{ 'admin_calendar.ongoing_reservations' }}</h3>
</div>
@ -57,7 +62,7 @@
</li>
</ul>
<div ng-show="reservations.length == 0" translate>{{ 'admin_calendar.no_reservations' }}</div>
<div class="m-t" ng-show="availability.lock"><i class="fa fa-ban"/> <span class="m-l-xs" translate>{{ 'admin_calendar.reservations_locked' }}</span></div>
<div class="m-t" ng-show="availability.lock"><i class="fa fa-ban"></i> <span class="m-l-xs" translate>{{ 'admin_calendar.reservations_locked' }}</span></div>
</div>
</div>
@ -75,28 +80,42 @@
</div>
</div>
<div class="widget panel b-a m m-t-lg" ng-if="availability">
<div class="widget panel b-a m m-t-lg" ng-if="availability" >
<div class="panel-heading b-b small">
<h3 translate>{{ 'admin_calendar.actions' }}</h3>
</div>
<div class="widget-content no-bg auto wrapper">
<div class="widget-content no-bg auto wrapper" ng-hide="availability.available_type == 'event'">
<button class="btn btn-default" ng-click="toggleLockReservations()">
<span ng-hide="availability.lock">
<i class="fa fa-stop" />
<i class="fa fa-stop"></i>
<span class="m-l-xs" translate>{{ 'admin_calendar.block_reservations' }}</span>
</span>
<span ng-show="availability.lock">
<i class="fa fa-play" />
<i class="fa fa-play"></i>
<span class="m-l-xs" translate>{{ 'admin_calendar.allow_reservations' }}</span>
</span>
</button>
<button class="btn btn-default m-t" ng-click="removeSlot()">
<span>
<i class="fa fa-trash" />
<i class="fa fa-trash"></i>
<span class="m-l-xs" translate>{{ 'admin_calendar.delete_slot' }}</span>
</span>
</button>
</div>
<div class="widget-content no-bg auto wrapper" ng-show="availability.available_type == 'event'">
<a class="btn btn-default m-t pointer" ui-sref="app.admin.events_edit({id: availability.event_id})">
<span>
<i class="fa fa-edit"></i>
<span class="m-l-xs" translate>{{ 'admin_calendar.edit_event' }}</span>
</span>
</a>
<a class="btn btn-default m-t pointer" ui-sref="app.admin.event_reservations({id: availability.event_id})">
<span>
<i class="fa fa-bookmark"></i>
<span class="m-l-xs" translate>{{ 'admin_calendar.view_reservations' }}</span>
</span>
</a>
</div>
</div>
</div>

View File

@ -14,9 +14,10 @@ class API::AvailabilitiesController < API::ApiController
start_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:start])
end_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:end]).end_of_day
@availabilities = Availability.includes(:machines, :tags, :trainings, :spaces)
.where.not(available_type: 'event')
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
@availabilities = @availabilities.where.not(available_type: 'event') unless Rails.application.secrets.events_in_calendar
@availabilities = @availabilities.where.not(available_type: 'space') if fablab_spaces_deactivated?
end

View File

@ -6,6 +6,7 @@ json.array!(@availabilities) do |availability|
json.available_type availability.available_type
json.machine_ids availability.machine_ids
json.training_ids availability.training_ids
json.event_id availability.event&.id
json.backgroundColor !availability.lock ? 'white' : '#f5f5f5'
json.borderColor availability_border_color(availability)
json.tag_ids availability.tag_ids

View File

@ -22,6 +22,7 @@ FABLAB_WITHOUT_ONLINE_PAYMENT: 'false'
FABLAB_WITHOUT_INVOICES: 'false'
PHONE_REQUIRED: 'true'
EVENTS_IN_CALENDAR: 'false'
SLOT_DURATION: '60'
DEFAULT_MAIL_FROM: Fab Manager Demo <noreply@fab-manager.com>

View File

@ -18,6 +18,7 @@ en:
trainings: "Trainings"
machines: "Machines"
spaces: "Spaces"
events: "Eventos"
availabilities: "Availabilities"
availabilities_notice: "Export to an Excel workbook every slots available for reservation, and their occupancy rate."
ongoing_reservations: "Ongoing reservations"
@ -83,6 +84,8 @@ en:
delete_this_and_next: "This slot and the following"
delete_all: "All slots"
event_in_the_past: "Unable to create a slot in the past."
edit_event: "Edit the event"
view_reservations: "View reservations"
project_elements:
# management of the projects' components

View File

@ -18,6 +18,7 @@ es:
trainings: "Formación"
machines: "Máquinas"
spaces: "Espacios"
events: "Eventos"
availabilities: "Disponibilidades"
availabilities_notice: "Exportar a un libro de trabajo de Excel cada ranura disponible para reserva, y su ratio de ocupación."
ongoing_reservations: "Reservas en curso"
@ -83,6 +84,8 @@ es:
delete_this_and_next: "This slot and the following" # translation_missing
delete_all: "All slots" # translation_missing
event_in_the_past: "Unable to create a slot in the past." # translation_missing
edit_event: "Edit the event" # translation_missing
view_reservations: "Ver reservas" # translation_missing
project_elements:
# management of the projects' components

View File

@ -18,6 +18,7 @@ fr:
trainings: "Formations"
machines: "Machines"
spaces: "Espaces"
events: "Évènements"
availabilities: "Disponibilités"
availabilities_notice: "Exporter dans un classeur Excel tous les créneaux ouverts à la réservation et leurs taux d'occupation."
ongoing_reservations: "Réservations en cours"
@ -83,6 +84,8 @@ fr:
delete_this_and_next: "Ce créneau et tous les suivants"
delete_all: "Tous les créneaux"
event_in_the_past: "Impossible de créer un créneau dans le passé."
edit_event: "Modifier l'évènement"
view_reservations: "Voir les réservations"
project_elements:
# gestion des éléments constituant les projets

View File

@ -18,6 +18,7 @@ pt:
trainings: "Treinamentos"
machines: "Máquinas"
spaces: "Espaços"
events: "Eventos"
availabilities: "Disponíveis"
availabilities_notice: "Exportar para Excel livro com todos os slots disponíveis para reserva, e suas ocupações."
ongoing_reservations: "Reservas em curso"
@ -83,6 +84,8 @@ pt:
delete_this_and_next: "This slot and the following" # translation_missing
delete_all: "All slots" # translation_missing
event_in_the_past: "Unable to create a slot in the past." # translation_missing
edit_event: "Edit the event" # translation_missing
view_reservations: "Ver reservas" # translation_missing
project_elements:
# management of the projects' components

View File

@ -21,6 +21,7 @@ development:
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
phone_required: <%= ENV["PHONE_REQUIRED"] %>
events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %>
slot_duration: <%= ENV["SLOT_DURATION"] %>
default_host: <%= ENV["DEFAULT_HOST"] %>
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
@ -65,7 +66,8 @@ test:
fablab_without_online_payments: false
fablab_without_invoices: false
phone_required: true
slot_duration: <%= ENV["SLOT_DURATION"] %>
events_in_calendar: false
slot_duration: 60
default_host: <%= ENV["DEFAULT_HOST"] %>
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
time_zone: Paris
@ -109,6 +111,7 @@ staging:
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
phone_required: <%= ENV["PHONE_REQUIRED"] %>
events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %>
slot_duration: <%= ENV["SLOT_DURATION"] %>
default_host: <%= ENV["DEFAULT_HOST"] %>
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
@ -164,6 +167,7 @@ production:
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
phone_required: <%= ENV["PHONE_REQUIRED"] %>
events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %>
slot_duration: <%= ENV["SLOT_DURATION"] %>
default_host: <%= ENV["DEFAULT_HOST"] %>
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>

View File

@ -107,6 +107,11 @@ This is useful if you have your own invoicing system and you want to prevent Fab
PHONE_REQUIRED
If set to 'false' the phone number won't be required to register a new user on the software.
<a name="EVENTS_IN_CALENDAR"></a>
EVENTS_IN_CALENDAR
If set to 'true', the admin calendar will display the scheduled events in the current view, as read-only items.
<a name="SLOT_DURATION"></a>
SLOT_DURATION

View File

@ -15,6 +15,7 @@ FABLAB_WITHOUT_ONLINE_PAYMENT=true
FABLAB_WITHOUT_INVOICES=false
PHONE_REQUIRED=false
EVENTS_IN_CALENDAR=false
SLOT_DURATION=60
DEFAULT_MAIL_FROM=Fab Manager Demo <noreply@fab-manager.com>