mirror of https://github.com/nextcloud/calendar
Compare commits
42 Commits
257b3d3c5d
...
4837945888
Author | SHA1 | Date |
---|---|---|
Grigory Vodyanov | 4837945888 | |
Anna | 4711c64baa | |
Anna | e2554308c7 | |
Anna Larch | dad5191d6f | |
Nextcloud bot | 6c930f2be0 | |
Richard Steinmetz | dea21127a1 | |
Richard Steinmetz | f4be9d57d0 | |
renovate[bot] | 3cb4d04baa | |
renovate[bot] | 9f1f3878ed | |
renovate[bot] | 2f8515d0fe | |
Richard Steinmetz | 27f98ba8ae | |
julia.kirschenheuter | 31dd0e9bc4 | |
Nextcloud bot | 96ae4cee81 | |
Richard Steinmetz | 25e264a3c8 | |
julia.kirschenheuter | 80e131a090 | |
Anna | df6aeef797 | |
Christoph Wurst | 3c0ec2ade0 | |
Richard Steinmetz | 72302840aa | |
renovate[bot] | e15a1a2663 | |
Richard Steinmetz | acf19b92b1 | |
renovate[bot] | e93fb34070 | |
Nextcloud bot | 6d1d2cb5ec | |
Anna Larch | 3acd93027c | |
Nextcloud bot | 5a7cfc1bf2 | |
Grigory Vodyanov | e959465999 | |
Grigory Vodyanov | 6b4845ac8d | |
Nextcloud bot | 6ea485f3fc | |
Hamza | d2f3d1953f | |
Hamza Mahjoubi | 110f94805e | |
Hamza | 97fce2ac52 | |
Hamza Mahjoubi | 4d624e7569 | |
Richard Steinmetz | ddf7a4e95a | |
Richard Steinmetz | 5ad0b84810 | |
Nextcloud bot | 7a17cce4e6 | |
Richard Steinmetz | 7e07384dc1 | |
Richard Steinmetz | af94950cbd | |
Nextcloud bot | 279088248d | |
Nextcloud bot | 48912fd899 | |
Nextcloud bot | a405475d40 | |
Nextcloud bot | 62717de62e | |
Nextcloud bot | a9f70025fd | |
Nextcloud bot | 8f389355ba |
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2024 Richard Steinmetz <richard@steinmetz.cloud>
|
||||
*
|
||||
* @author Richard Steinmetz <richard@steinmetz.cloud>
|
||||
*
|
||||
* @license AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
export default {}
|
|
@ -163,8 +163,7 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.multiselect,
|
||||
input[type=number] {
|
||||
.multiselect {
|
||||
min-width: 100px;
|
||||
width: 25%;
|
||||
}
|
||||
|
|
139
l10n/ast.js
139
l10n/ast.js
|
@ -1,62 +1,153 @@
|
|||
OC.L10N.register(
|
||||
"calendar",
|
||||
{
|
||||
"Provided email-address is too long" : "La direición de corréu electrónicu apurrida ye mui llonga",
|
||||
"User-Session unexpectedly expired" : "La sesión del usuariu caducó inesperadamente",
|
||||
"Provided email-address is not valid" : "La direición de corréu electrónicu apurrida nun ye válida",
|
||||
"%s has published the calendar »%s«" : "%s espublizó'l calendariu «%s»",
|
||||
"Unexpected error sending email. Please contact your administrator." : "Prodúxose un error inesperáu al unviar el mensaxe. Ponte en contautu col alministrador.",
|
||||
"Successfully sent email to %1$s" : "El mensaxe unvióse a %1$s correutamente",
|
||||
"Hello," : "Hola,",
|
||||
"We wanted to inform you that %s has published the calendar »%s«." : "Queremos informate que %s espublizó'l calendariu «%s».",
|
||||
"Open »%s«" : "Abrir «%s»",
|
||||
"Cheers!" : "¡Saludos!",
|
||||
"Upcoming events" : "Eventos próximos",
|
||||
"More events" : "Más eventos",
|
||||
"No more events today" : "Nun hai más eventos pa güei",
|
||||
"No upcoming events" : "Nun hai eventos próximos",
|
||||
"%1$s with %2$s" : "%1$s con %2$s",
|
||||
"Calendar" : "Calendariu",
|
||||
"New booking {booking}" : "Reserva nueva «{booking}»",
|
||||
"Appointments" : "Cites",
|
||||
"%1$s - %2$s" : "%1$s - %2$s",
|
||||
"Confirm" : "Confirmar",
|
||||
"Date:" : "Data:",
|
||||
"You will receive a link with the confirmation email" : "Vas recibir un enllaz col mensaxe de confirmación",
|
||||
"Where:" : "Ónde:",
|
||||
"Comment:" : "Comentariu:",
|
||||
"Previous day" : "Día anterior",
|
||||
"Previous week" : "Selmana pasada",
|
||||
"Previous year" : "Añu pasáu",
|
||||
"Previous month" : "Mes pasáu",
|
||||
"Next day" : "Día siguiente",
|
||||
"Next week" : "La selmana que vien",
|
||||
"Next year" : "Añu siguiente",
|
||||
"Next month" : "Mes siguiente",
|
||||
"Event" : "Eventu",
|
||||
"Create new event" : "Crear un eventu",
|
||||
"Today" : "Güei",
|
||||
"Day" : "Día",
|
||||
"Week" : "Selmana",
|
||||
"Month" : "Mes",
|
||||
"Year" : "Añu",
|
||||
"List" : "Llista",
|
||||
"Preview" : "Previsualizar",
|
||||
"Copy link" : "Copiar l'enllaz",
|
||||
"Edit" : "Editar",
|
||||
"Delete" : "Desaniciar",
|
||||
"Untitled calendar" : "Calendariu ensin títulu",
|
||||
"Edit and share calendar" : "Editar y comaprtir el calendariu",
|
||||
"Edit calendar" : "Editar el calendariu",
|
||||
"Disable calendar \"{calendar}\"" : "Desactivar el calendariu «{calendar}»",
|
||||
"Disable untitled calendar" : "Desactivar el calendariu ensin títulu",
|
||||
"Enable calendar \"{calendar}\"" : "¿Quies activar el calendariu «{calendar}»?",
|
||||
"Enable untitled calendar" : "Activar el calendariu ensin títulu",
|
||||
"An error occurred, unable to change visibility of the calendar." : "Prodúxose un error, nun ye posible camudar la visibilidá del calendariu.",
|
||||
"_Unsharing the calendar in {countdown} second_::_Unsharing the calendar in {countdown} seconds_" : ["Va dexar de compartise'l calendariu en {countdown} segundu","Va dexar de compartise'l calendariu en {countdown} segundos"],
|
||||
"_Deleting the calendar in {countdown} second_::_Deleting the calendar in {countdown} seconds_" : ["Va desaniciase'l calendariu en {countdown} segundu","Va desaniciase'l calendariu en {countdown} segundos"],
|
||||
"New calendar" : "Calendariu nuevu",
|
||||
"Name for new calendar" : "Nome del calendariu nuevu",
|
||||
"Creating calendar …" : "Creando'l calendariu…",
|
||||
"Creating subscription …" : "Creando la soscripción…",
|
||||
"An error occurred, unable to create the calendar." : "Prodúxose un error, nun ye posible crear el calendariu.",
|
||||
"Copy subscription link" : "Copiar l'enllaz de soscripción",
|
||||
"Copying link …" : "Copiando l'enllaz …",
|
||||
"Copied link" : "L'enllaz copióse",
|
||||
"Could not copy link" : "Nun se pudo copiar l'enllaz",
|
||||
"Export" : "Esportar",
|
||||
"Calendar link copied to clipboard." : "L'enllaz del calendariu copióse nel cartafueyu.",
|
||||
"Calendar link could not be copied to clipboard." : "L'enllaz del calendariu nun se pudo copiar nel cartafueyu.",
|
||||
"Trash bin" : "Papelera",
|
||||
"Loading deleted items." : "Cargando los elementos desaniciaos.",
|
||||
"You do not have any deleted items." : "Nun tienes nengún elementu desaniciáu.",
|
||||
"Name" : "Nome",
|
||||
"Deleted" : "Desanicióse",
|
||||
"Restore" : "Restaurar",
|
||||
"Delete permanently" : "Desaniciar permanentemente",
|
||||
"Empty trash bin" : "Balerar la papelera",
|
||||
"Untitled item" : "Elementu ensin nome",
|
||||
"Unknown calendar" : "Calendariu desconocíu",
|
||||
"Could not load deleted calendars and objects" : "Nun se pudieron desaniciar los calendarios y los oxetos",
|
||||
"Could not restore calendar or event" : "Nun se pudo restaurar el calendariu o l'eventu",
|
||||
"Do you really want to empty the trash bin?" : "¿De xuru que quies balerar la papelera de reciclaxe?",
|
||||
"Could not update calendar order." : "Nun se pudo anovar l'orde del calendariu.",
|
||||
"Internal link" : "Enllaz internu",
|
||||
"A private link that can be used with external clients" : "Un enllaz priváu que se pue usar con veceros esternos",
|
||||
"Copy internal link" : "Copiar l'enllaz internu",
|
||||
"Share link" : "Compartir l'enllaz",
|
||||
"Copy public link" : "Copiar l'enllaz públicu",
|
||||
"Send link to calendar via email" : "Unviar l'enllaz del calendariu per corréu electrónicu",
|
||||
"Enter one address" : "Introduz una direción",
|
||||
"Sending email …" : "Unviando'l mensaxe…",
|
||||
"Copy embedding code" : "Copiar el códigu pa empotrar",
|
||||
"Copying code …" : "Copiando'l códigu …",
|
||||
"Copied code" : "Copióse'l códigu",
|
||||
"Could not copy code" : "Nun se pudo copiar el códigu",
|
||||
"Delete share link" : "Desaniciar esti enllaz d'usu compartíu",
|
||||
"Deleting share link …" : "Desaniciando l'enllaz d'usu compartíu…",
|
||||
"An error occurred, unable to publish calendar." : "Prodúxose un error, nun ye posible espublizar el calendariu.",
|
||||
"An error occurred, unable to send email." : "Prodúxose un error, nun ye posible unviar el mensaxe.",
|
||||
"Embed code copied to clipboard." : "El códigu incrustáu copióse nel cartafueyu.",
|
||||
"Embed code could not be copied to clipboard." : "El códigu incrustáu nun se pudo copiar nel cartafueyu.",
|
||||
"Unshare with {displayName}" : "Dexar de compartir con {displayName}",
|
||||
"An error occurred while unsharing the calendar." : "Prodúxose un error mentanto se dexaba de compartir el calendariu.",
|
||||
"An error occurred, unable to change the permission of the share." : "Prodúxose un error, nun ye posible camudar el permisu del elementu compartíu.",
|
||||
"Share with users or groups" : "Compartir con usuarios o grupos",
|
||||
"No users or groups" : "Nun hai nengún usuariu nin grupu",
|
||||
"Calendar name …" : "Nome del calendariu…",
|
||||
"Share calendar" : "Compartir el calendariu",
|
||||
"Save" : "Guardar",
|
||||
"Failed to save calendar name and color" : "Nun se pue guardar el nome y el color del calendariu",
|
||||
"Import calendars" : "Importar calendarios",
|
||||
"Please select a calendar to import into …" : "Seleiciona un calendariu al qu'importar …",
|
||||
"Filename" : "Nome del ficheru",
|
||||
"Cancel" : "Encaboxar",
|
||||
"Invalid location selected" : "Seleicionóse una llocalización inválida",
|
||||
"Automatic" : "Automáticu",
|
||||
"or" : "o",
|
||||
"Navigation" : "Navegación",
|
||||
"Previous period" : "Periodu anterior",
|
||||
"Next period" : "Periodu siguiente",
|
||||
"Views" : "Vistes",
|
||||
"Day view" : "Vista de díes",
|
||||
"Week view" : "Vista de selmanes",
|
||||
"Month view" : "Vista de meses",
|
||||
"Year view" : "Vista d'años",
|
||||
"List view" : "Vista de llista",
|
||||
"Actions" : "Aiciones",
|
||||
"Create event" : "Crear un eventu",
|
||||
"Show shortcuts" : "Amosar los atayos",
|
||||
"Editor" : "Editor",
|
||||
"Close editor" : "Zarrar l'editor",
|
||||
"Save edited event" : "Guardar l'eventu editáu",
|
||||
"Delete edited event" : "Desaniciar l'eventu desaniciáu",
|
||||
"Duplicate event" : "Duplicar l'eventu",
|
||||
"Enable birthday calendar" : "Activar el calendariu de los cumpleaños",
|
||||
"Show tasks in calendar" : "Amosar les xeres nel calendariu",
|
||||
"Enable simplified editor" : "Activar l'editor simplificáu",
|
||||
"Limit the number of events displayed in the monthly view" : "Llendar el númberu d'eventos amosaos na vista de meses",
|
||||
"Show weekends" : "Amosar les fines de selmana",
|
||||
"Show week numbers" : "Amosar los númberos de selmana",
|
||||
"Default reminder" : "Recordatoriu predetermináu",
|
||||
"Copy primary CalDAV address" : "Copiar la direición CalDAV primaria",
|
||||
"Copy iOS/macOS CalDAV address" : "Copiar la direición CalDAV d'iOS/macOS",
|
||||
"Personal availability settings" : "Configuración de la disponibilidá personal",
|
||||
"Show keyboard shortcuts" : "Amosar los atayos del tecáu",
|
||||
"Calendar settings" : "Configuración del calendariu",
|
||||
"No reminder" : "Nun hai nengún recordatoriu",
|
||||
"Failed to save default calendar" : "Nun se pue guardar el calendariu predetermináu",
|
||||
"CalDAV link copied to clipboard." : "L'enllaz CalDAV copióse nel cartafueyu.",
|
||||
"CalDAV link could not be copied to clipboard." : "L'enllaz CalDAV nun se pudo copiar nel cartafueyu.",
|
||||
"_{duration} minute_::_{duration} minutes_" : ["{duration} minutu","{duration} minutos"],
|
||||
"0 minutes" : "0 minutos",
|
||||
"_{duration} hour_::_{duration} hours_" : ["{duration} hora","{duration} hores"],
|
||||
|
@ -65,9 +156,12 @@ OC.L10N.register(
|
|||
"_{duration} month_::_{duration} months_" : ["{duration} mes","{duration} meses"],
|
||||
"_{duration} year_::_{duration} years_" : ["{duration} añu","{duration} años"],
|
||||
"Location" : "Llocalización",
|
||||
"Create a Talk room" : "Crear una sala de Talk",
|
||||
"Description" : "Descripción",
|
||||
"Visibility" : "Visibilidá",
|
||||
"Duration" : "Duración",
|
||||
"to" : "pa",
|
||||
"Delete slot" : "Desaniciar la ralura",
|
||||
"Add" : "Amestar",
|
||||
"Monday" : "Llunes",
|
||||
"Tuesday" : "Martes",
|
||||
|
@ -81,25 +175,57 @@ OC.L10N.register(
|
|||
"Your email address" : "La to direición de corréu electrónicu",
|
||||
"Notification" : "Avisu",
|
||||
"Email" : "Corréu electrónicu",
|
||||
"Audio notification" : "Avisu d'audiu",
|
||||
"Other notification" : "Otru avisu",
|
||||
"Edit time" : "Editar la hora",
|
||||
"Save time" : "Guardar la hora",
|
||||
"Remove reminder" : "Quitar el recordatoriu",
|
||||
"_second_::_seconds_" : ["segundu","segundos"],
|
||||
"_minute_::_minutes_" : ["minutu","minutos"],
|
||||
"_hour_::_hours_" : ["hora","hores"],
|
||||
"_day_::_days_" : ["día","díes"],
|
||||
"_week_::_weeks_" : ["selmana","selmanes"],
|
||||
"Delete file" : "Desaniciar el ficheru",
|
||||
"Invitation accepted" : "Invitación aceptada",
|
||||
"Available" : "Disponible",
|
||||
"Not available" : "Nun ta disponible",
|
||||
"Invitation declined" : "Invitación refugada",
|
||||
"Checking availability" : "Comprobando la disponibilidá",
|
||||
"Awaiting response" : "Esperando pola rempuesta",
|
||||
"Has not responded to {organizerName}'s invitation yet" : "Nun respondió a la invitación de: {organizerName}",
|
||||
"Find a time" : "Atopar una hora",
|
||||
"with" : "con",
|
||||
"Available times:" : "Hores disponibles:",
|
||||
"Suggestion accepted" : "Suxerencia aceptada",
|
||||
"Done" : "Fecho",
|
||||
"Busy" : "Ocupáu",
|
||||
"Out of office" : "Fuera de la oficina",
|
||||
"Accept" : "Aceptar",
|
||||
"Decline" : "Refugar",
|
||||
"Tentative" : "Provisional",
|
||||
"The invitation has been accepted successfully." : "La invitación aceptóse correutamente.",
|
||||
"Failed to accept the invitation." : "Nun se pue aceptar la invitación",
|
||||
"The invitation has been declined successfully." : "La invitación refugóse correutamente.",
|
||||
"Failed to decline the invitation." : "Nun se pue refugar la invitación",
|
||||
"Your participation has been marked as tentative." : "La to participación marcóse como provisional.",
|
||||
"Failed to set the participation status to tentative." : "Nun se pudo afitar l'estáu de la participación a provisional",
|
||||
"Attendees" : "Asistentes",
|
||||
"No attendees yet" : "Nun hai nengún asistente",
|
||||
"You do not own this calendar, so you cannot add attendees to this event" : "Esti calendariu nun te pertenez, polo que nun pues amestar asistentes a esti eventu",
|
||||
"Error creating Talk room" : "Hebo un error al crear la sala de Talk",
|
||||
"_%n more guest_::_%n more guests_" : ["%n convidáu más","%n convidaos más"],
|
||||
"Remove group" : "Quitar el grupu",
|
||||
"_%n member_::_%n members_" : ["%n miembru","%n miembros"],
|
||||
"No match found" : "Nun s'atopó nenguna coincidencia",
|
||||
"Remove color" : "Quitar el color",
|
||||
"Event title" : "Títulu del eventu",
|
||||
"All day" : "Tol día",
|
||||
"Repeat" : "Repitir",
|
||||
"never" : "enxamás",
|
||||
"first" : "primer",
|
||||
"third" : "tercer",
|
||||
"fourth" : "cuartu",
|
||||
"fifth" : "quintu",
|
||||
"_month_::_months_" : ["mes","meses"],
|
||||
"_year_::_years_" : ["añu","años"],
|
||||
"Suggestions" : "Suxerencies",
|
||||
|
@ -108,6 +234,7 @@ OC.L10N.register(
|
|||
"_{seatingCapacity} seat_::_{seatingCapacity} seats_" : ["{seatingCapacity} asientu","{seatingCapacity} asientos"],
|
||||
"Projector" : "Proyeutor",
|
||||
"Whiteboard" : "Pizarra",
|
||||
"More details" : "Mas detalles",
|
||||
"Pick a date" : "Escueyi una data",
|
||||
"Please enter a valid date" : "Introduz una data válida",
|
||||
"Global" : "Global",
|
||||
|
@ -132,15 +259,27 @@ OC.L10N.register(
|
|||
"_Every %n week_::_Every %n weeks_" : ["Cada %n selmana","Cada %n selmanes"],
|
||||
"_Every %n month_::_Every %n months_" : ["Cada %n mes","Cada %n meses"],
|
||||
"_Every %n year_::_Every %n years_" : ["Cada %n añu","Cada %n años"],
|
||||
"_%n time_::_%n times_" : ["%n vegada","%n vegaes"],
|
||||
"Untitled task" : "Xera ensin títulu",
|
||||
"Please ask your administrator to enable the Tasks App." : "Pidi al alministrador qu'active l'aplicación Xeres.",
|
||||
"W" : "S",
|
||||
"%n more" : "%n más",
|
||||
"_+%n more_::_+%n more_" : ["+%n más","+%n más"],
|
||||
"No events" : "Nun hai nengún eventu",
|
||||
"Failed to save event" : "Nun se pue guardar l'eventu",
|
||||
"When shared show full event" : "Cuando se comparta amosar l'eventu completu",
|
||||
"When shared show only busy" : "Cuando se comparta amosar namás si ta ocupáu",
|
||||
"When shared hide this event" : "Cuando se comparta anubrir l'eventu",
|
||||
"Status" : "Estáu",
|
||||
"Canceled" : "Anulóse",
|
||||
"Categories" : "Categories",
|
||||
"Error while sharing file" : "Hebo un error mentanto se compartía'l ficheru",
|
||||
"Error while sharing file with user" : "Hebo un error mentanto se compartía'l ficheru col usuariu",
|
||||
"An error occurred during getting file information" : "Prodúxose un error demientres se consiguía la información del ficheru",
|
||||
"Chat room for event" : "Sala de charra pal eventu",
|
||||
"An error occurred, unable to delete the calendar." : "Prodúxose un error, nun ye posible desaniciar el calendariu",
|
||||
"Imported {filename}" : "Importóse «{filename}»",
|
||||
"This is an event reminder." : "Esto ye un recordatoriu del eventu.",
|
||||
"User not found" : "Nun s'atopó l'usuariu"
|
||||
},
|
||||
"nplurals=2; plural=(n != 1);");
|
||||
|
|
139
l10n/ast.json
139
l10n/ast.json
|
@ -1,60 +1,151 @@
|
|||
{ "translations": {
|
||||
"Provided email-address is too long" : "La direición de corréu electrónicu apurrida ye mui llonga",
|
||||
"User-Session unexpectedly expired" : "La sesión del usuariu caducó inesperadamente",
|
||||
"Provided email-address is not valid" : "La direición de corréu electrónicu apurrida nun ye válida",
|
||||
"%s has published the calendar »%s«" : "%s espublizó'l calendariu «%s»",
|
||||
"Unexpected error sending email. Please contact your administrator." : "Prodúxose un error inesperáu al unviar el mensaxe. Ponte en contautu col alministrador.",
|
||||
"Successfully sent email to %1$s" : "El mensaxe unvióse a %1$s correutamente",
|
||||
"Hello," : "Hola,",
|
||||
"We wanted to inform you that %s has published the calendar »%s«." : "Queremos informate que %s espublizó'l calendariu «%s».",
|
||||
"Open »%s«" : "Abrir «%s»",
|
||||
"Cheers!" : "¡Saludos!",
|
||||
"Upcoming events" : "Eventos próximos",
|
||||
"More events" : "Más eventos",
|
||||
"No more events today" : "Nun hai más eventos pa güei",
|
||||
"No upcoming events" : "Nun hai eventos próximos",
|
||||
"%1$s with %2$s" : "%1$s con %2$s",
|
||||
"Calendar" : "Calendariu",
|
||||
"New booking {booking}" : "Reserva nueva «{booking}»",
|
||||
"Appointments" : "Cites",
|
||||
"%1$s - %2$s" : "%1$s - %2$s",
|
||||
"Confirm" : "Confirmar",
|
||||
"Date:" : "Data:",
|
||||
"You will receive a link with the confirmation email" : "Vas recibir un enllaz col mensaxe de confirmación",
|
||||
"Where:" : "Ónde:",
|
||||
"Comment:" : "Comentariu:",
|
||||
"Previous day" : "Día anterior",
|
||||
"Previous week" : "Selmana pasada",
|
||||
"Previous year" : "Añu pasáu",
|
||||
"Previous month" : "Mes pasáu",
|
||||
"Next day" : "Día siguiente",
|
||||
"Next week" : "La selmana que vien",
|
||||
"Next year" : "Añu siguiente",
|
||||
"Next month" : "Mes siguiente",
|
||||
"Event" : "Eventu",
|
||||
"Create new event" : "Crear un eventu",
|
||||
"Today" : "Güei",
|
||||
"Day" : "Día",
|
||||
"Week" : "Selmana",
|
||||
"Month" : "Mes",
|
||||
"Year" : "Añu",
|
||||
"List" : "Llista",
|
||||
"Preview" : "Previsualizar",
|
||||
"Copy link" : "Copiar l'enllaz",
|
||||
"Edit" : "Editar",
|
||||
"Delete" : "Desaniciar",
|
||||
"Untitled calendar" : "Calendariu ensin títulu",
|
||||
"Edit and share calendar" : "Editar y comaprtir el calendariu",
|
||||
"Edit calendar" : "Editar el calendariu",
|
||||
"Disable calendar \"{calendar}\"" : "Desactivar el calendariu «{calendar}»",
|
||||
"Disable untitled calendar" : "Desactivar el calendariu ensin títulu",
|
||||
"Enable calendar \"{calendar}\"" : "¿Quies activar el calendariu «{calendar}»?",
|
||||
"Enable untitled calendar" : "Activar el calendariu ensin títulu",
|
||||
"An error occurred, unable to change visibility of the calendar." : "Prodúxose un error, nun ye posible camudar la visibilidá del calendariu.",
|
||||
"_Unsharing the calendar in {countdown} second_::_Unsharing the calendar in {countdown} seconds_" : ["Va dexar de compartise'l calendariu en {countdown} segundu","Va dexar de compartise'l calendariu en {countdown} segundos"],
|
||||
"_Deleting the calendar in {countdown} second_::_Deleting the calendar in {countdown} seconds_" : ["Va desaniciase'l calendariu en {countdown} segundu","Va desaniciase'l calendariu en {countdown} segundos"],
|
||||
"New calendar" : "Calendariu nuevu",
|
||||
"Name for new calendar" : "Nome del calendariu nuevu",
|
||||
"Creating calendar …" : "Creando'l calendariu…",
|
||||
"Creating subscription …" : "Creando la soscripción…",
|
||||
"An error occurred, unable to create the calendar." : "Prodúxose un error, nun ye posible crear el calendariu.",
|
||||
"Copy subscription link" : "Copiar l'enllaz de soscripción",
|
||||
"Copying link …" : "Copiando l'enllaz …",
|
||||
"Copied link" : "L'enllaz copióse",
|
||||
"Could not copy link" : "Nun se pudo copiar l'enllaz",
|
||||
"Export" : "Esportar",
|
||||
"Calendar link copied to clipboard." : "L'enllaz del calendariu copióse nel cartafueyu.",
|
||||
"Calendar link could not be copied to clipboard." : "L'enllaz del calendariu nun se pudo copiar nel cartafueyu.",
|
||||
"Trash bin" : "Papelera",
|
||||
"Loading deleted items." : "Cargando los elementos desaniciaos.",
|
||||
"You do not have any deleted items." : "Nun tienes nengún elementu desaniciáu.",
|
||||
"Name" : "Nome",
|
||||
"Deleted" : "Desanicióse",
|
||||
"Restore" : "Restaurar",
|
||||
"Delete permanently" : "Desaniciar permanentemente",
|
||||
"Empty trash bin" : "Balerar la papelera",
|
||||
"Untitled item" : "Elementu ensin nome",
|
||||
"Unknown calendar" : "Calendariu desconocíu",
|
||||
"Could not load deleted calendars and objects" : "Nun se pudieron desaniciar los calendarios y los oxetos",
|
||||
"Could not restore calendar or event" : "Nun se pudo restaurar el calendariu o l'eventu",
|
||||
"Do you really want to empty the trash bin?" : "¿De xuru que quies balerar la papelera de reciclaxe?",
|
||||
"Could not update calendar order." : "Nun se pudo anovar l'orde del calendariu.",
|
||||
"Internal link" : "Enllaz internu",
|
||||
"A private link that can be used with external clients" : "Un enllaz priváu que se pue usar con veceros esternos",
|
||||
"Copy internal link" : "Copiar l'enllaz internu",
|
||||
"Share link" : "Compartir l'enllaz",
|
||||
"Copy public link" : "Copiar l'enllaz públicu",
|
||||
"Send link to calendar via email" : "Unviar l'enllaz del calendariu per corréu electrónicu",
|
||||
"Enter one address" : "Introduz una direción",
|
||||
"Sending email …" : "Unviando'l mensaxe…",
|
||||
"Copy embedding code" : "Copiar el códigu pa empotrar",
|
||||
"Copying code …" : "Copiando'l códigu …",
|
||||
"Copied code" : "Copióse'l códigu",
|
||||
"Could not copy code" : "Nun se pudo copiar el códigu",
|
||||
"Delete share link" : "Desaniciar esti enllaz d'usu compartíu",
|
||||
"Deleting share link …" : "Desaniciando l'enllaz d'usu compartíu…",
|
||||
"An error occurred, unable to publish calendar." : "Prodúxose un error, nun ye posible espublizar el calendariu.",
|
||||
"An error occurred, unable to send email." : "Prodúxose un error, nun ye posible unviar el mensaxe.",
|
||||
"Embed code copied to clipboard." : "El códigu incrustáu copióse nel cartafueyu.",
|
||||
"Embed code could not be copied to clipboard." : "El códigu incrustáu nun se pudo copiar nel cartafueyu.",
|
||||
"Unshare with {displayName}" : "Dexar de compartir con {displayName}",
|
||||
"An error occurred while unsharing the calendar." : "Prodúxose un error mentanto se dexaba de compartir el calendariu.",
|
||||
"An error occurred, unable to change the permission of the share." : "Prodúxose un error, nun ye posible camudar el permisu del elementu compartíu.",
|
||||
"Share with users or groups" : "Compartir con usuarios o grupos",
|
||||
"No users or groups" : "Nun hai nengún usuariu nin grupu",
|
||||
"Calendar name …" : "Nome del calendariu…",
|
||||
"Share calendar" : "Compartir el calendariu",
|
||||
"Save" : "Guardar",
|
||||
"Failed to save calendar name and color" : "Nun se pue guardar el nome y el color del calendariu",
|
||||
"Import calendars" : "Importar calendarios",
|
||||
"Please select a calendar to import into …" : "Seleiciona un calendariu al qu'importar …",
|
||||
"Filename" : "Nome del ficheru",
|
||||
"Cancel" : "Encaboxar",
|
||||
"Invalid location selected" : "Seleicionóse una llocalización inválida",
|
||||
"Automatic" : "Automáticu",
|
||||
"or" : "o",
|
||||
"Navigation" : "Navegación",
|
||||
"Previous period" : "Periodu anterior",
|
||||
"Next period" : "Periodu siguiente",
|
||||
"Views" : "Vistes",
|
||||
"Day view" : "Vista de díes",
|
||||
"Week view" : "Vista de selmanes",
|
||||
"Month view" : "Vista de meses",
|
||||
"Year view" : "Vista d'años",
|
||||
"List view" : "Vista de llista",
|
||||
"Actions" : "Aiciones",
|
||||
"Create event" : "Crear un eventu",
|
||||
"Show shortcuts" : "Amosar los atayos",
|
||||
"Editor" : "Editor",
|
||||
"Close editor" : "Zarrar l'editor",
|
||||
"Save edited event" : "Guardar l'eventu editáu",
|
||||
"Delete edited event" : "Desaniciar l'eventu desaniciáu",
|
||||
"Duplicate event" : "Duplicar l'eventu",
|
||||
"Enable birthday calendar" : "Activar el calendariu de los cumpleaños",
|
||||
"Show tasks in calendar" : "Amosar les xeres nel calendariu",
|
||||
"Enable simplified editor" : "Activar l'editor simplificáu",
|
||||
"Limit the number of events displayed in the monthly view" : "Llendar el númberu d'eventos amosaos na vista de meses",
|
||||
"Show weekends" : "Amosar les fines de selmana",
|
||||
"Show week numbers" : "Amosar los númberos de selmana",
|
||||
"Default reminder" : "Recordatoriu predetermináu",
|
||||
"Copy primary CalDAV address" : "Copiar la direición CalDAV primaria",
|
||||
"Copy iOS/macOS CalDAV address" : "Copiar la direición CalDAV d'iOS/macOS",
|
||||
"Personal availability settings" : "Configuración de la disponibilidá personal",
|
||||
"Show keyboard shortcuts" : "Amosar los atayos del tecáu",
|
||||
"Calendar settings" : "Configuración del calendariu",
|
||||
"No reminder" : "Nun hai nengún recordatoriu",
|
||||
"Failed to save default calendar" : "Nun se pue guardar el calendariu predetermináu",
|
||||
"CalDAV link copied to clipboard." : "L'enllaz CalDAV copióse nel cartafueyu.",
|
||||
"CalDAV link could not be copied to clipboard." : "L'enllaz CalDAV nun se pudo copiar nel cartafueyu.",
|
||||
"_{duration} minute_::_{duration} minutes_" : ["{duration} minutu","{duration} minutos"],
|
||||
"0 minutes" : "0 minutos",
|
||||
"_{duration} hour_::_{duration} hours_" : ["{duration} hora","{duration} hores"],
|
||||
|
@ -63,9 +154,12 @@
|
|||
"_{duration} month_::_{duration} months_" : ["{duration} mes","{duration} meses"],
|
||||
"_{duration} year_::_{duration} years_" : ["{duration} añu","{duration} años"],
|
||||
"Location" : "Llocalización",
|
||||
"Create a Talk room" : "Crear una sala de Talk",
|
||||
"Description" : "Descripción",
|
||||
"Visibility" : "Visibilidá",
|
||||
"Duration" : "Duración",
|
||||
"to" : "pa",
|
||||
"Delete slot" : "Desaniciar la ralura",
|
||||
"Add" : "Amestar",
|
||||
"Monday" : "Llunes",
|
||||
"Tuesday" : "Martes",
|
||||
|
@ -79,25 +173,57 @@
|
|||
"Your email address" : "La to direición de corréu electrónicu",
|
||||
"Notification" : "Avisu",
|
||||
"Email" : "Corréu electrónicu",
|
||||
"Audio notification" : "Avisu d'audiu",
|
||||
"Other notification" : "Otru avisu",
|
||||
"Edit time" : "Editar la hora",
|
||||
"Save time" : "Guardar la hora",
|
||||
"Remove reminder" : "Quitar el recordatoriu",
|
||||
"_second_::_seconds_" : ["segundu","segundos"],
|
||||
"_minute_::_minutes_" : ["minutu","minutos"],
|
||||
"_hour_::_hours_" : ["hora","hores"],
|
||||
"_day_::_days_" : ["día","díes"],
|
||||
"_week_::_weeks_" : ["selmana","selmanes"],
|
||||
"Delete file" : "Desaniciar el ficheru",
|
||||
"Invitation accepted" : "Invitación aceptada",
|
||||
"Available" : "Disponible",
|
||||
"Not available" : "Nun ta disponible",
|
||||
"Invitation declined" : "Invitación refugada",
|
||||
"Checking availability" : "Comprobando la disponibilidá",
|
||||
"Awaiting response" : "Esperando pola rempuesta",
|
||||
"Has not responded to {organizerName}'s invitation yet" : "Nun respondió a la invitación de: {organizerName}",
|
||||
"Find a time" : "Atopar una hora",
|
||||
"with" : "con",
|
||||
"Available times:" : "Hores disponibles:",
|
||||
"Suggestion accepted" : "Suxerencia aceptada",
|
||||
"Done" : "Fecho",
|
||||
"Busy" : "Ocupáu",
|
||||
"Out of office" : "Fuera de la oficina",
|
||||
"Accept" : "Aceptar",
|
||||
"Decline" : "Refugar",
|
||||
"Tentative" : "Provisional",
|
||||
"The invitation has been accepted successfully." : "La invitación aceptóse correutamente.",
|
||||
"Failed to accept the invitation." : "Nun se pue aceptar la invitación",
|
||||
"The invitation has been declined successfully." : "La invitación refugóse correutamente.",
|
||||
"Failed to decline the invitation." : "Nun se pue refugar la invitación",
|
||||
"Your participation has been marked as tentative." : "La to participación marcóse como provisional.",
|
||||
"Failed to set the participation status to tentative." : "Nun se pudo afitar l'estáu de la participación a provisional",
|
||||
"Attendees" : "Asistentes",
|
||||
"No attendees yet" : "Nun hai nengún asistente",
|
||||
"You do not own this calendar, so you cannot add attendees to this event" : "Esti calendariu nun te pertenez, polo que nun pues amestar asistentes a esti eventu",
|
||||
"Error creating Talk room" : "Hebo un error al crear la sala de Talk",
|
||||
"_%n more guest_::_%n more guests_" : ["%n convidáu más","%n convidaos más"],
|
||||
"Remove group" : "Quitar el grupu",
|
||||
"_%n member_::_%n members_" : ["%n miembru","%n miembros"],
|
||||
"No match found" : "Nun s'atopó nenguna coincidencia",
|
||||
"Remove color" : "Quitar el color",
|
||||
"Event title" : "Títulu del eventu",
|
||||
"All day" : "Tol día",
|
||||
"Repeat" : "Repitir",
|
||||
"never" : "enxamás",
|
||||
"first" : "primer",
|
||||
"third" : "tercer",
|
||||
"fourth" : "cuartu",
|
||||
"fifth" : "quintu",
|
||||
"_month_::_months_" : ["mes","meses"],
|
||||
"_year_::_years_" : ["añu","años"],
|
||||
"Suggestions" : "Suxerencies",
|
||||
|
@ -106,6 +232,7 @@
|
|||
"_{seatingCapacity} seat_::_{seatingCapacity} seats_" : ["{seatingCapacity} asientu","{seatingCapacity} asientos"],
|
||||
"Projector" : "Proyeutor",
|
||||
"Whiteboard" : "Pizarra",
|
||||
"More details" : "Mas detalles",
|
||||
"Pick a date" : "Escueyi una data",
|
||||
"Please enter a valid date" : "Introduz una data válida",
|
||||
"Global" : "Global",
|
||||
|
@ -130,15 +257,27 @@
|
|||
"_Every %n week_::_Every %n weeks_" : ["Cada %n selmana","Cada %n selmanes"],
|
||||
"_Every %n month_::_Every %n months_" : ["Cada %n mes","Cada %n meses"],
|
||||
"_Every %n year_::_Every %n years_" : ["Cada %n añu","Cada %n años"],
|
||||
"_%n time_::_%n times_" : ["%n vegada","%n vegaes"],
|
||||
"Untitled task" : "Xera ensin títulu",
|
||||
"Please ask your administrator to enable the Tasks App." : "Pidi al alministrador qu'active l'aplicación Xeres.",
|
||||
"W" : "S",
|
||||
"%n more" : "%n más",
|
||||
"_+%n more_::_+%n more_" : ["+%n más","+%n más"],
|
||||
"No events" : "Nun hai nengún eventu",
|
||||
"Failed to save event" : "Nun se pue guardar l'eventu",
|
||||
"When shared show full event" : "Cuando se comparta amosar l'eventu completu",
|
||||
"When shared show only busy" : "Cuando se comparta amosar namás si ta ocupáu",
|
||||
"When shared hide this event" : "Cuando se comparta anubrir l'eventu",
|
||||
"Status" : "Estáu",
|
||||
"Canceled" : "Anulóse",
|
||||
"Categories" : "Categories",
|
||||
"Error while sharing file" : "Hebo un error mentanto se compartía'l ficheru",
|
||||
"Error while sharing file with user" : "Hebo un error mentanto se compartía'l ficheru col usuariu",
|
||||
"An error occurred during getting file information" : "Prodúxose un error demientres se consiguía la información del ficheru",
|
||||
"Chat room for event" : "Sala de charra pal eventu",
|
||||
"An error occurred, unable to delete the calendar." : "Prodúxose un error, nun ye posible desaniciar el calendariu",
|
||||
"Imported {filename}" : "Importóse «{filename}»",
|
||||
"This is an event reminder." : "Esto ye un recordatoriu del eventu.",
|
||||
"User not found" : "Nun s'atopó l'usuariu"
|
||||
},"pluralForm" :"nplurals=2; plural=(n != 1);"
|
||||
}
|
|
@ -11,6 +11,7 @@ OC.L10N.register(
|
|||
"Calendar" : "Calendario",
|
||||
"Appointments" : "Citas",
|
||||
"Confirm" : "Confirmar",
|
||||
"Date:" : "Fecha:",
|
||||
"Where:" : "Dónde:",
|
||||
"A Calendar app for Nextcloud" : "Una aplicación de Calendario para Nextcloud",
|
||||
"Today" : "Hoy",
|
||||
|
@ -23,6 +24,7 @@ OC.L10N.register(
|
|||
"Copy link" : "Copiar liga",
|
||||
"Edit" : "Editar",
|
||||
"Delete" : "Borrar",
|
||||
"Untitled calendar" : "Calendario sin título",
|
||||
"New calendar" : "Nuevo calendario",
|
||||
"Export" : "Exportar",
|
||||
"Name" : "Nombre",
|
||||
|
@ -53,6 +55,7 @@ OC.L10N.register(
|
|||
"Visibility" : "Visibilidad",
|
||||
"Duration" : "Duración",
|
||||
"to" : "para",
|
||||
"Delete slot" : "Eliminar ranura",
|
||||
"Add" : "Agregar",
|
||||
"Monday" : "Lunes",
|
||||
"Tuesday" : "Martes",
|
||||
|
@ -61,6 +64,7 @@ OC.L10N.register(
|
|||
"Friday" : "Viernes",
|
||||
"Saturday" : "Sábado",
|
||||
"Sunday" : "Domingo",
|
||||
"Weekdays" : "Días laborales",
|
||||
"Update" : "Actualizar",
|
||||
"Your email address" : "Tu dirección de correo electrónico",
|
||||
"Notification" : "Notificación",
|
||||
|
@ -74,6 +78,8 @@ OC.L10N.register(
|
|||
"Checking availability" : "Comprobando disponibilidad",
|
||||
"Availability of attendees, resources and rooms" : "Disponibilidad de asistentes, recursos y salas",
|
||||
"Done" : "Terminado",
|
||||
"Busy" : "Ocupado",
|
||||
"Out of office" : "Fuera de la oficina",
|
||||
"Unknown" : "Desconocido",
|
||||
"Accept" : "Aceptar",
|
||||
"Decline" : "Rechazar",
|
||||
|
@ -90,15 +96,19 @@ OC.L10N.register(
|
|||
"Pick a date" : "Elige una fecha",
|
||||
"Global" : "Global",
|
||||
"Subscribe" : "Suscríbete",
|
||||
"Time:" : "Hora:",
|
||||
"Personal" : "Personal",
|
||||
"Create a new event" : "Crear un nuevo evento",
|
||||
"Details" : "Detalles",
|
||||
"Invite" : "Invitar",
|
||||
"Resources" : "Recursos",
|
||||
"Close" : "Cerrar",
|
||||
"Untitled event" : "Evento sin título",
|
||||
"Anniversary" : "Aniversario",
|
||||
"Week {number} of {year}" : "Semana {number} de {year}",
|
||||
"Daily" : "Diariamente",
|
||||
"Weekly" : "Semanalmente",
|
||||
"Untitled task" : "Tarea sin título",
|
||||
"Other" : "Otro",
|
||||
"When shared show full event" : "Al compartir, mostrar el evento completo",
|
||||
"When shared show only busy" : "Al compartir, mostrar sólo como ocupado ",
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
"Calendar" : "Calendario",
|
||||
"Appointments" : "Citas",
|
||||
"Confirm" : "Confirmar",
|
||||
"Date:" : "Fecha:",
|
||||
"Where:" : "Dónde:",
|
||||
"A Calendar app for Nextcloud" : "Una aplicación de Calendario para Nextcloud",
|
||||
"Today" : "Hoy",
|
||||
|
@ -21,6 +22,7 @@
|
|||
"Copy link" : "Copiar liga",
|
||||
"Edit" : "Editar",
|
||||
"Delete" : "Borrar",
|
||||
"Untitled calendar" : "Calendario sin título",
|
||||
"New calendar" : "Nuevo calendario",
|
||||
"Export" : "Exportar",
|
||||
"Name" : "Nombre",
|
||||
|
@ -51,6 +53,7 @@
|
|||
"Visibility" : "Visibilidad",
|
||||
"Duration" : "Duración",
|
||||
"to" : "para",
|
||||
"Delete slot" : "Eliminar ranura",
|
||||
"Add" : "Agregar",
|
||||
"Monday" : "Lunes",
|
||||
"Tuesday" : "Martes",
|
||||
|
@ -59,6 +62,7 @@
|
|||
"Friday" : "Viernes",
|
||||
"Saturday" : "Sábado",
|
||||
"Sunday" : "Domingo",
|
||||
"Weekdays" : "Días laborales",
|
||||
"Update" : "Actualizar",
|
||||
"Your email address" : "Tu dirección de correo electrónico",
|
||||
"Notification" : "Notificación",
|
||||
|
@ -72,6 +76,8 @@
|
|||
"Checking availability" : "Comprobando disponibilidad",
|
||||
"Availability of attendees, resources and rooms" : "Disponibilidad de asistentes, recursos y salas",
|
||||
"Done" : "Terminado",
|
||||
"Busy" : "Ocupado",
|
||||
"Out of office" : "Fuera de la oficina",
|
||||
"Unknown" : "Desconocido",
|
||||
"Accept" : "Aceptar",
|
||||
"Decline" : "Rechazar",
|
||||
|
@ -88,15 +94,19 @@
|
|||
"Pick a date" : "Elige una fecha",
|
||||
"Global" : "Global",
|
||||
"Subscribe" : "Suscríbete",
|
||||
"Time:" : "Hora:",
|
||||
"Personal" : "Personal",
|
||||
"Create a new event" : "Crear un nuevo evento",
|
||||
"Details" : "Detalles",
|
||||
"Invite" : "Invitar",
|
||||
"Resources" : "Recursos",
|
||||
"Close" : "Cerrar",
|
||||
"Untitled event" : "Evento sin título",
|
||||
"Anniversary" : "Aniversario",
|
||||
"Week {number} of {year}" : "Semana {number} de {year}",
|
||||
"Daily" : "Diariamente",
|
||||
"Weekly" : "Semanalmente",
|
||||
"Untitled task" : "Tarea sin título",
|
||||
"Other" : "Otro",
|
||||
"When shared show full event" : "Al compartir, mostrar el evento completo",
|
||||
"When shared show only busy" : "Al compartir, mostrar sólo como ocupado ",
|
||||
|
|
|
@ -222,6 +222,7 @@ OC.L10N.register(
|
|||
"Friday" : "venres",
|
||||
"Saturday" : "sábado",
|
||||
"Sunday" : "domingo",
|
||||
"Weekdays" : "Días laborables",
|
||||
"Add time before and after the event" : "Engadir tempo antes e após o evento",
|
||||
"Before the event" : "Antes do evento",
|
||||
"After the event" : "Após o evento",
|
||||
|
|
|
@ -220,6 +220,7 @@
|
|||
"Friday" : "venres",
|
||||
"Saturday" : "sábado",
|
||||
"Sunday" : "domingo",
|
||||
"Weekdays" : "Días laborables",
|
||||
"Add time before and after the event" : "Engadir tempo antes e após o evento",
|
||||
"Before the event" : "Antes do evento",
|
||||
"After the event" : "Após o evento",
|
||||
|
|
|
@ -3,6 +3,7 @@ OC.L10N.register(
|
|||
{
|
||||
"Cheers!" : "Prost!",
|
||||
"Calendar" : "Kalenner",
|
||||
"Confirm" : "Konfirméieren",
|
||||
"Today" : "Haut",
|
||||
"Day" : "Dag",
|
||||
"Week" : "Woch",
|
||||
|
@ -16,12 +17,14 @@ OC.L10N.register(
|
|||
"Deleted" : "Geläscht",
|
||||
"Restore" : "Zrécksetzen",
|
||||
"Delete permanently" : "Permanent läschen",
|
||||
"Empty trash bin" : "Eidel Dreckskëscht",
|
||||
"Share link" : "Link deelen",
|
||||
"can edit" : "kann änneren",
|
||||
"Share with users or groups" : "Mat Benotzer oder Gruppen deelen",
|
||||
"Save" : "Späicheren",
|
||||
"Cancel" : "Ofbriechen",
|
||||
"Automatic" : "Automatesch",
|
||||
"List view" : "Lëscht Vue",
|
||||
"Actions" : "Aktiounen",
|
||||
"Location" : "Uert",
|
||||
"Description" : "Beschreiwung",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{ "translations": {
|
||||
"Cheers!" : "Prost!",
|
||||
"Calendar" : "Kalenner",
|
||||
"Confirm" : "Konfirméieren",
|
||||
"Today" : "Haut",
|
||||
"Day" : "Dag",
|
||||
"Week" : "Woch",
|
||||
|
@ -14,12 +15,14 @@
|
|||
"Deleted" : "Geläscht",
|
||||
"Restore" : "Zrécksetzen",
|
||||
"Delete permanently" : "Permanent läschen",
|
||||
"Empty trash bin" : "Eidel Dreckskëscht",
|
||||
"Share link" : "Link deelen",
|
||||
"can edit" : "kann änneren",
|
||||
"Share with users or groups" : "Mat Benotzer oder Gruppen deelen",
|
||||
"Save" : "Späicheren",
|
||||
"Cancel" : "Ofbriechen",
|
||||
"Automatic" : "Automatesch",
|
||||
"List view" : "Lëscht Vue",
|
||||
"Actions" : "Aktiounen",
|
||||
"Location" : "Uert",
|
||||
"Description" : "Beschreiwung",
|
||||
|
|
|
@ -25,12 +25,12 @@ OC.L10N.register(
|
|||
"%1$s - %2$s" : "%1$s - %2$s",
|
||||
"Prepare for %s" : "Voorbereiden op %s",
|
||||
"Follow up for %s" : "Follow-up voor %s",
|
||||
"Your appointment \"%s\" with %s needs confirmation" : "Je afspraak \"%s\" met %smoet nog bevestigd worden ",
|
||||
"Your appointment \"%s\" with %s needs confirmation" : "Je afspraak \"%s\" met %s moet nog bevestigd worden",
|
||||
"Dear %s, please confirm your booking" : "Beste %s, bevestig alsjeblieft je boeking",
|
||||
"Confirm" : "Bevestigen",
|
||||
"This confirmation link expires in %s hours." : "Deze bevestigingslink verloopt over %s uur.",
|
||||
"If you wish to cancel the appointment after all, please contact your organizer by replying to this email or by visiting their profile page." : "Als je de afspraak toch wilt annuleren, neem dan contact op met de organisator door te antwoorden op deze e-mail of door hun profielpagina te bezoeken.",
|
||||
"Your appointment \"%s\" with %s has been accepted" : "Ja afspraak \"%s\" met %sis geaccepteerd",
|
||||
"Your appointment \"%s\" with %s has been accepted" : "Je afspraak \"%s\" met %sis geaccepteerd",
|
||||
"Dear %s, your booking has been accepted." : "Beste %s, je boeking is aanvaard.",
|
||||
"Appointment for:" : "Afspraak voor:",
|
||||
"Date:" : "Datum:",
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
"%1$s - %2$s" : "%1$s - %2$s",
|
||||
"Prepare for %s" : "Voorbereiden op %s",
|
||||
"Follow up for %s" : "Follow-up voor %s",
|
||||
"Your appointment \"%s\" with %s needs confirmation" : "Je afspraak \"%s\" met %smoet nog bevestigd worden ",
|
||||
"Your appointment \"%s\" with %s needs confirmation" : "Je afspraak \"%s\" met %s moet nog bevestigd worden",
|
||||
"Dear %s, please confirm your booking" : "Beste %s, bevestig alsjeblieft je boeking",
|
||||
"Confirm" : "Bevestigen",
|
||||
"This confirmation link expires in %s hours." : "Deze bevestigingslink verloopt over %s uur.",
|
||||
"If you wish to cancel the appointment after all, please contact your organizer by replying to this email or by visiting their profile page." : "Als je de afspraak toch wilt annuleren, neem dan contact op met de organisator door te antwoorden op deze e-mail of door hun profielpagina te bezoeken.",
|
||||
"Your appointment \"%s\" with %s has been accepted" : "Ja afspraak \"%s\" met %sis geaccepteerd",
|
||||
"Your appointment \"%s\" with %s has been accepted" : "Je afspraak \"%s\" met %sis geaccepteerd",
|
||||
"Dear %s, your booking has been accepted." : "Beste %s, je boeking is aanvaard.",
|
||||
"Appointment for:" : "Afspraak voor:",
|
||||
"Date:" : "Datum:",
|
||||
|
|
|
@ -29,6 +29,7 @@ OC.L10N.register(
|
|||
"Update" : "Ažuriraj",
|
||||
"Email" : "email",
|
||||
"Done" : "Gotovo",
|
||||
"Out of office" : "Van kancelarije",
|
||||
"Unknown" : "Nepoznato",
|
||||
"never" : "never",
|
||||
"Details" : "Detalji",
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"Update" : "Ažuriraj",
|
||||
"Email" : "email",
|
||||
"Done" : "Gotovo",
|
||||
"Out of office" : "Van kancelarije",
|
||||
"Unknown" : "Nepoznato",
|
||||
"never" : "never",
|
||||
"Details" : "Detalji",
|
||||
|
|
|
@ -74,7 +74,7 @@ OC.L10N.register(
|
|||
"Enable untitled calendar" : "Увімкнути календар без назви",
|
||||
"An error occurred, unable to change visibility of the calendar." : "Помилка: неможливо змінити подання календаря.",
|
||||
"_Unsharing the calendar in {countdown} second_::_Unsharing the calendar in {countdown} seconds_" : ["Поширення календаря буде відмінено через {countdown} секунду","Поширення календаря буде відмінено через {countdown} секунд","Поширення календаря буде відмінено через {countdown} секунд","Календар буде від'єднано за {countdown} секунд"],
|
||||
"_Deleting the calendar in {countdown} second_::_Deleting the calendar in {countdown} seconds_" : ["Календар буде видалено через {countdown} секунду","Календар буде видалено через {countdown} секунд","Календар буде видалено через {countdown} секунд","Календар буде вилучено через {countdown} секунд"],
|
||||
"_Deleting the calendar in {countdown} second_::_Deleting the calendar in {countdown} seconds_" : ["Календар буде вилучено через {countdown} секунду","Календар буде вилучено через {countdown} секунди","Календар буде вилучено через {countdown} секунд","Календар буде вилучено через {countdown} секунд"],
|
||||
"New calendar" : "Додати календар",
|
||||
"Name for new calendar" : "Назва нового календаря",
|
||||
"Creating calendar …" : "Створення календаря...",
|
||||
|
@ -255,7 +255,7 @@ OC.L10N.register(
|
|||
"Edit time" : "Редагувати час",
|
||||
"Save time" : "Зберегти час",
|
||||
"Remove reminder" : "Прибрати нагадування",
|
||||
"on" : "у",
|
||||
"on" : "о",
|
||||
"at" : "о",
|
||||
"+ Add reminder" : "+ Додати нагадування",
|
||||
"Add reminder" : "Додати нагадування",
|
||||
|
@ -440,7 +440,7 @@ OC.L10N.register(
|
|||
"Invite" : "Запросити",
|
||||
"Resources" : "Ресурси",
|
||||
"_User requires access to your file_::_Users require access to your file_" : ["Потрібно надати доступ до вашого файлу.","Потрібно надати доступ до вашого файлу.","Потрібно надати доступ до вашого файлу.","Потрібно надати доступ до вашого файлу."],
|
||||
"_Attachment requires shared access_::_Attachments requiring shared access_" : ["Для доступу до додатку потрібний спільний доступ.","Для доступу до додатків потрібний спільний доступ.","Для доступу до додатків потрібний спільний доступ.","Для доступу до додатків потрібний спільний доступ."],
|
||||
"_Attachment requires shared access_::_Attachments requiring shared access_" : ["Для доступу до застосунку потрібний спільний доступ.","Для доступу до застосунків потрібний спільний доступ.","Для доступу до застосунків потрібний спільний доступ.","Для доступу до застосунків потрібний спільний доступ."],
|
||||
"Close" : "Закрити",
|
||||
"Untitled event" : "Подія без назви",
|
||||
"Subscribe to {name}" : "Підписатися на {name}",
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
"Enable untitled calendar" : "Увімкнути календар без назви",
|
||||
"An error occurred, unable to change visibility of the calendar." : "Помилка: неможливо змінити подання календаря.",
|
||||
"_Unsharing the calendar in {countdown} second_::_Unsharing the calendar in {countdown} seconds_" : ["Поширення календаря буде відмінено через {countdown} секунду","Поширення календаря буде відмінено через {countdown} секунд","Поширення календаря буде відмінено через {countdown} секунд","Календар буде від'єднано за {countdown} секунд"],
|
||||
"_Deleting the calendar in {countdown} second_::_Deleting the calendar in {countdown} seconds_" : ["Календар буде видалено через {countdown} секунду","Календар буде видалено через {countdown} секунд","Календар буде видалено через {countdown} секунд","Календар буде вилучено через {countdown} секунд"],
|
||||
"_Deleting the calendar in {countdown} second_::_Deleting the calendar in {countdown} seconds_" : ["Календар буде вилучено через {countdown} секунду","Календар буде вилучено через {countdown} секунди","Календар буде вилучено через {countdown} секунд","Календар буде вилучено через {countdown} секунд"],
|
||||
"New calendar" : "Додати календар",
|
||||
"Name for new calendar" : "Назва нового календаря",
|
||||
"Creating calendar …" : "Створення календаря...",
|
||||
|
@ -253,7 +253,7 @@
|
|||
"Edit time" : "Редагувати час",
|
||||
"Save time" : "Зберегти час",
|
||||
"Remove reminder" : "Прибрати нагадування",
|
||||
"on" : "у",
|
||||
"on" : "о",
|
||||
"at" : "о",
|
||||
"+ Add reminder" : "+ Додати нагадування",
|
||||
"Add reminder" : "Додати нагадування",
|
||||
|
@ -438,7 +438,7 @@
|
|||
"Invite" : "Запросити",
|
||||
"Resources" : "Ресурси",
|
||||
"_User requires access to your file_::_Users require access to your file_" : ["Потрібно надати доступ до вашого файлу.","Потрібно надати доступ до вашого файлу.","Потрібно надати доступ до вашого файлу.","Потрібно надати доступ до вашого файлу."],
|
||||
"_Attachment requires shared access_::_Attachments requiring shared access_" : ["Для доступу до додатку потрібний спільний доступ.","Для доступу до додатків потрібний спільний доступ.","Для доступу до додатків потрібний спільний доступ.","Для доступу до додатків потрібний спільний доступ."],
|
||||
"_Attachment requires shared access_::_Attachments requiring shared access_" : ["Для доступу до застосунку потрібний спільний доступ.","Для доступу до застосунків потрібний спільний доступ.","Для доступу до застосунків потрібний спільний доступ.","Для доступу до застосунків потрібний спільний доступ."],
|
||||
"Close" : "Закрити",
|
||||
"Untitled event" : "Подія без назви",
|
||||
"Subscribe to {name}" : "Підписатися на {name}",
|
||||
|
|
|
@ -214,7 +214,7 @@ class BookingController extends Controller {
|
|||
);
|
||||
}
|
||||
|
||||
return JsonResponse::success($booking);
|
||||
return JsonResponse::success();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,12 +27,13 @@ declare(strict_types=1);
|
|||
namespace OCA\Calendar\Dashboard;
|
||||
|
||||
use OCP\Dashboard\IAPIWidgetV2;
|
||||
use OCP\Dashboard\IReloadableWidget;
|
||||
use OCP\Dashboard\Model\WidgetItems;
|
||||
|
||||
/**
|
||||
* Requires Nextcloud >= 27.1.0
|
||||
*/
|
||||
class CalendarWidgetV2 extends CalendarWidget implements IAPIWidgetV2 {
|
||||
class CalendarWidgetV2 extends CalendarWidget implements IAPIWidgetV2, IReloadableWidget {
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
|
@ -68,4 +69,11 @@ class CalendarWidgetV2 extends CalendarWidget implements IAPIWidgetV2 {
|
|||
public function getIconClass(): string {
|
||||
return 'icon-calendar-dark';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getReloadInterval(): int {
|
||||
return 600;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,24 +73,55 @@ class ReferenceProvider extends ADiscoverableReferenceProvider {
|
|||
public function matchReference(string $referenceText): bool {
|
||||
$start = $this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID);
|
||||
$startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID);
|
||||
if (preg_match('/^' . preg_quote($start, '/') . '\/p\/[a-zA-Z0-9]+$/i', $referenceText) === 1 || preg_match('/^' . preg_quote($startIndex, '/') . '\/p\/[a-zA-Z0-9]+$/i', $referenceText) === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$start = $this->urlGenerator->getAbsoluteURL('/remote.php/dav/calendars');
|
||||
if (preg_match('/^' . preg_quote($start, '/') . '\/[a-zA-Z0-9-]+\/[a-zA-Z0-9-]+\/$/i', $referenceText) === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return preg_match('/^' . preg_quote($start, '/') . '\/p\/[a-zA-Z0-9]+$/i', $referenceText) === 1 || preg_match('/^' . preg_quote($startIndex, '/') . '\/p\/[a-zA-Z0-9]+$/i', $referenceText) === 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function resolveReference(string $referenceText): ?IReference {
|
||||
if ($this->matchReference($referenceText)) {
|
||||
$token = $this->getCalendarTokenFromLink($referenceText);
|
||||
|
||||
$type = $this->getType($referenceText);
|
||||
$reference = new Reference($referenceText);
|
||||
$reference->setTitle('calendar');
|
||||
$reference->setDescription($token);
|
||||
$reference->setRichObject(
|
||||
'calendar_widget',
|
||||
[
|
||||
'title' => 'calendar',
|
||||
'token' => $token,
|
||||
'url' => $referenceText,]
|
||||
);
|
||||
$reference->setDescription('calendar widget');
|
||||
|
||||
switch ($type) {
|
||||
case 'public':
|
||||
$token = $this->getCalendarTokenFromLink($referenceText);
|
||||
$url = $this->getUrlFromLink($token, 'public');
|
||||
$reference->setRichObject(
|
||||
'calendar_widget',
|
||||
[
|
||||
'title' => 'calendar',
|
||||
'token' => $token,
|
||||
'isPublic' => true,
|
||||
'url' => $url,
|
||||
]
|
||||
);
|
||||
break;
|
||||
case 'private':
|
||||
$url = $this->getUrlFromLink($referenceText, 'private');
|
||||
$reference->setRichObject(
|
||||
'calendar_widget',
|
||||
[
|
||||
'title' => 'calendar',
|
||||
'isPublic' => false,
|
||||
'url' => $url,
|
||||
]
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return $reference;
|
||||
}
|
||||
|
@ -99,14 +130,31 @@ class ReferenceProvider extends ADiscoverableReferenceProvider {
|
|||
}
|
||||
|
||||
private function getCalendarTokenFromLink(string $url): ?string {
|
||||
|
||||
|
||||
if (preg_match('/\/p\/([a-zA-Z0-9]+)/', $url, $output_array)) {
|
||||
return $output_array[1];
|
||||
}
|
||||
return $url;
|
||||
return null;
|
||||
|
||||
}
|
||||
private function getUrlFromLink(string $data, string $type): ?string {
|
||||
if ($type === 'public') {
|
||||
return "{$this->urlGenerator->getWebroot()}/remote.php/dav/public-calendars/{$data}/";
|
||||
} elseif ($type === 'private' && preg_match('/\/remote.php\/dav\/calendars\/([a-zA-Z0-9-]+)\/([a-zA-Z0-9-]+)\//', $data, $output_array)) {
|
||||
return $this->urlGenerator->getWebroot().$output_array[0];
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private function getType(string $url): string {
|
||||
if (preg_match('/\/p\/([a-zA-Z0-9]+)/', $url) === 1) {
|
||||
return 'public';
|
||||
}
|
||||
if (preg_match('/\/dav\/calendars\/([^\/]+)\/([^\/]+)/', $url) === 1) {
|
||||
return 'private';
|
||||
}
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
public function getCachePrefix(string $referenceId): string {
|
||||
return '';
|
||||
|
|
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
|
@ -45,19 +45,19 @@
|
|||
"@fullcalendar/resource-timeline": "6.1.11",
|
||||
"@fullcalendar/timegrid": "6.1.11",
|
||||
"@fullcalendar/vue": "6.1.11",
|
||||
"@nextcloud/auth": "^2.2.1",
|
||||
"@nextcloud/auth": "^2.3.0",
|
||||
"@nextcloud/axios": "^2.4.0",
|
||||
"@nextcloud/calendar-availability-vue": "^2.2.0",
|
||||
"@nextcloud/calendar-js": "^6.1.0",
|
||||
"@nextcloud/cdav-library": "^1.3.0",
|
||||
"@nextcloud/dialogs": "^4.2.6",
|
||||
"@nextcloud/event-bus": "^3.1.0",
|
||||
"@nextcloud/dialogs": "^5.3.1",
|
||||
"@nextcloud/event-bus": "^3.2.0",
|
||||
"@nextcloud/initial-state": "^2.1.0",
|
||||
"@nextcloud/l10n": "^2.2.0",
|
||||
"@nextcloud/logger": "^2.7.0",
|
||||
"@nextcloud/moment": "^1.3.1",
|
||||
"@nextcloud/router": "^3.0.0",
|
||||
"@nextcloud/vue": "^8.7.1",
|
||||
"@nextcloud/router": "^3.0.1",
|
||||
"@nextcloud/vue": "^8.11.2",
|
||||
"@nextcloud/vue-dashboard": "^2.0.1",
|
||||
"autosize": "^6.0.1",
|
||||
"color-convert": "^2.0.1",
|
||||
|
@ -118,7 +118,8 @@
|
|||
],
|
||||
"moduleNameMapper": {
|
||||
"^@/(.*)$": "<rootDir>/src/$1",
|
||||
"^ical.js": "<rootDir>/node_modules/ical.js"
|
||||
"^ical.js": "<rootDir>/node_modules/ical.js",
|
||||
"\\.(css|less|scss|sass)$": "<rootDir>/__mocks__/css.js"
|
||||
},
|
||||
"transform": {
|
||||
".*\\.js$": "<rootDir>/node_modules/babel-jest",
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
],
|
||||
"labels": [
|
||||
"dependencies",
|
||||
"3 - to review"
|
||||
"3. to review"
|
||||
],
|
||||
"commitMessageAction": "Bump",
|
||||
"commitMessageTopic": "{{depName}}",
|
||||
|
@ -23,8 +23,7 @@
|
|||
"ignoreUnstable": false,
|
||||
"baseBranches": [
|
||||
"main",
|
||||
"stable4.4",
|
||||
"stable4.3"
|
||||
"stable4.7"
|
||||
],
|
||||
"enabledManagers": [
|
||||
"composer",
|
||||
|
@ -71,7 +70,7 @@
|
|||
"platformAutomerge": true,
|
||||
"labels": [
|
||||
"dependencies",
|
||||
"4 - to release"
|
||||
"4. to release"
|
||||
],
|
||||
"reviewers": []
|
||||
},
|
||||
|
@ -81,7 +80,7 @@
|
|||
"automerge": false,
|
||||
"labels": [
|
||||
"dependencies",
|
||||
"3 - to review"
|
||||
"3. to review"
|
||||
],
|
||||
"reviewers": [
|
||||
"GretaD",
|
||||
|
|
|
@ -24,12 +24,15 @@
|
|||
<template>
|
||||
<div class="share-item">
|
||||
<AccountMultiple v-if="sharee.isGroup" :size="20" class="share-item__group-icon" />
|
||||
<IconCircle v-else-if="sharee.isCircle" />
|
||||
<AccountGroupIcon v-else-if="sharee.isCircle" :size="20" class="share-item__team-icon" />
|
||||
<NcAvatar v-else :user="sharee.userId" :display-name="sharee.displayName" />
|
||||
|
||||
<p class="share-item__label">
|
||||
<div class="share-item__label">
|
||||
{{ sharee.displayName }}
|
||||
</p>
|
||||
<p>
|
||||
{{ shareeEmail }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input :id="`${id}-can-edit`"
|
||||
:disabled="updatingSharee"
|
||||
|
@ -54,7 +57,7 @@
|
|||
<script>
|
||||
import { NcActions, NcActionButton, NcAvatar } from '@nextcloud/vue'
|
||||
import AccountMultiple from 'vue-material-design-icons/AccountMultiple.vue'
|
||||
import IconCircle from '../../Icons/IconCircles.vue'
|
||||
import AccountGroupIcon from 'vue-material-design-icons/AccountGroup.vue'
|
||||
import Delete from 'vue-material-design-icons/Delete.vue'
|
||||
import {
|
||||
showInfo,
|
||||
|
@ -67,7 +70,7 @@ export default {
|
|||
NcActions,
|
||||
NcActionButton,
|
||||
NcAvatar,
|
||||
IconCircle,
|
||||
AccountGroupIcon,
|
||||
AccountMultiple,
|
||||
Delete,
|
||||
},
|
||||
|
@ -85,12 +88,28 @@ export default {
|
|||
return {
|
||||
id: randomId(),
|
||||
updatingSharee: false,
|
||||
shareeEmail: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
uid() {
|
||||
return this._uid
|
||||
},
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
displayName() {
|
||||
if (this.sharee.isCircle) {
|
||||
return t('calendar', '{teamDisplayName} (Team)', {
|
||||
teamDisplayName: this.sharee.displayName
|
||||
})
|
||||
}
|
||||
|
||||
return this.sharee.displayName
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateShareeEmail()
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
|
@ -133,6 +152,20 @@ export default {
|
|||
this.updatingSharee = false
|
||||
}
|
||||
},
|
||||
|
||||
async updateShareeEmail() {
|
||||
if (this.sharee.isGroup || this.sharee.isCircle) {
|
||||
return
|
||||
}
|
||||
|
||||
const shareeUrl = this.sharee.uri.replace('principal:', '/remote.php/dav/') + '/'
|
||||
|
||||
await this.$store.dispatch('fetchPrincipalByUrl', { url: shareeUrl })
|
||||
|
||||
const principal = this.$store.getters.getPrincipalByUrl(shareeUrl)
|
||||
|
||||
this.shareeEmail = principal.emailAddress
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -143,7 +176,8 @@ export default {
|
|||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
&__group-icon {
|
||||
&__group-icon,
|
||||
&__team-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 16px;
|
||||
|
@ -151,8 +185,21 @@ export default {
|
|||
background-color: var(--color-text-maxcontrast);
|
||||
}
|
||||
|
||||
&__team-icon {
|
||||
// Upstream icon is slightly misaligned when centered using flex
|
||||
:deep(svg) {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
flex: 1 auto;
|
||||
flex-direction: column;
|
||||
|
||||
p {
|
||||
color: var(--color-text-lighter);
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -43,21 +43,40 @@
|
|||
<template #no-options>
|
||||
<span>{{ $t('calendar', 'No users or groups') }}</span>
|
||||
</template>
|
||||
<template #option="sharee">
|
||||
<div class="share-item">
|
||||
<AccountMultiple v-if="sharee.isGroup" :size="20" class="share-item__group-icon" />
|
||||
<AccountGroupIcon v-else-if="sharee.isCircle" :size="20" class="share-item__team-icon" />
|
||||
<NcAvatar v-else :user="sharee.userId" :display-name="sharee.displayName" />
|
||||
|
||||
<div class="share-item__label">
|
||||
{{ sharee.displayName }}
|
||||
<p>
|
||||
{{ sharee.email }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</NcSelect>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { NcSelect } from '@nextcloud/vue'
|
||||
import { NcAvatar, NcSelect } from '@nextcloud/vue'
|
||||
import { principalPropertySearchByDisplaynameOrEmail } from '../../../services/caldavService.js'
|
||||
import HttpClient from '@nextcloud/axios'
|
||||
import debounce from 'debounce'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
import { urldecode } from '../../../utils/url.js'
|
||||
import AccountMultiple from 'vue-material-design-icons/AccountMultiple.vue'
|
||||
import AccountGroupIcon from 'vue-material-design-icons/AccountGroup.vue'
|
||||
|
||||
export default {
|
||||
name: 'SharingSearch',
|
||||
components: {
|
||||
NcAvatar,
|
||||
AccountGroupIcon,
|
||||
AccountMultiple,
|
||||
NcSelect,
|
||||
},
|
||||
props: {
|
||||
|
@ -141,6 +160,7 @@ export default {
|
|||
this.inputGiven = false
|
||||
this.isLoading = false
|
||||
}
|
||||
|
||||
}, 500),
|
||||
/**
|
||||
*
|
||||
|
@ -188,6 +208,7 @@ export default {
|
|||
isCircle: false,
|
||||
isNoUser: isGroup,
|
||||
search: query,
|
||||
email: result.email,
|
||||
})
|
||||
return list
|
||||
}, [])
|
||||
|
@ -255,4 +276,30 @@ export default {
|
|||
flex: 1 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.share-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
|
||||
&__group-icon,
|
||||
&__team-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 16px;
|
||||
color: white;
|
||||
background-color: var(--color-text-maxcontrast);
|
||||
}
|
||||
|
||||
&__label {
|
||||
flex: 1 auto;
|
||||
flex-direction: column;
|
||||
|
||||
p {
|
||||
color: var(--color-text-lighter);
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -22,9 +22,10 @@
|
|||
-->
|
||||
|
||||
<template>
|
||||
<FullCalendar ref="fullCalendar"
|
||||
<FullCalendar v-if="calendarOptions"
|
||||
ref="fullCalendar"
|
||||
:class="isWidget? 'fullcalendar-widget': ''"
|
||||
:options="options" />
|
||||
:options="calendarOptions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -77,6 +78,10 @@ export default {
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
/**
|
||||
* Whether or not the user is authenticated
|
||||
*/
|
||||
|
@ -89,6 +94,7 @@ export default {
|
|||
return {
|
||||
updateTodayJob: null,
|
||||
updateTodayJobPreviousDate: null,
|
||||
calendarOptions: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -154,6 +160,13 @@ export default {
|
|||
}
|
||||
},
|
||||
eventSources() {
|
||||
if (this.isWidget) {
|
||||
const calendar = this.$store.getters.getCalendarByUrl(this.url)
|
||||
if (!calendar) {
|
||||
return []
|
||||
}
|
||||
return [calendar].map(eventSource(this.$store))
|
||||
}
|
||||
return this.$store.getters.enabledCalendars.map(eventSource(this.$store))
|
||||
},
|
||||
widgetView() {
|
||||
|
@ -194,6 +207,22 @@ export default {
|
|||
const calendarApi = this.$refs.fullCalendar.getApi()
|
||||
calendarApi.gotoDate(getYYYYMMDDFromFirstdayParam(newDate))
|
||||
},
|
||||
eventSources(sources, oldSources) {
|
||||
const newSources = sources.filter(source => !oldSources.map(oldSource => oldSource.id).includes(source.id))
|
||||
const removedSources = oldSources.filter(oldSource => !sources.map(source => source.id).includes(oldSource.id))
|
||||
|
||||
// Hackity hack! Unfortunately, calendarOptions.eventSources is not reactive ...
|
||||
// Ref https://fullcalendar.io/docs/Calendar-addEventSource
|
||||
// TODO: Find a better/safer way to prevent duplicated event sources
|
||||
const calendarApi = this.$refs.fullCalendar.getApi()
|
||||
for (const source of newSources) {
|
||||
calendarApi.addEventSource(source)
|
||||
}
|
||||
const eventSources = calendarApi.getEventSources()
|
||||
for (const source of removedSources) {
|
||||
eventSources.find(x => x.id === source.id)?.remove()
|
||||
}
|
||||
},
|
||||
modificationCount: debounce(function() {
|
||||
const calendarApi = this.$refs.fullCalendar.getApi()
|
||||
calendarApi.refetchEvents()
|
||||
|
@ -213,7 +242,7 @@ export default {
|
|||
* we have to register a resize-observer here, that will automatically
|
||||
* update the fullCalendar size, when the available space changes.
|
||||
*/
|
||||
mounted() {
|
||||
mounted() {
|
||||
if (window.ResizeObserver) {
|
||||
const resizeObserver = new ResizeObserver(debounce(() => {
|
||||
this.$refs.fullCalendar
|
||||
|
@ -225,6 +254,8 @@ export default {
|
|||
}
|
||||
},
|
||||
async created() {
|
||||
this.calendarOptions = await this.options
|
||||
|
||||
this.updateTodayJob = setInterval(() => {
|
||||
const newDate = getYYYYMMDDFromFirstdayParam('now')
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ import HelpCircleIcon from 'vue-material-design-icons/HelpCircle.vue'
|
|||
import InviteesListSearch from '../Invitees/InviteesListSearch.vue'
|
||||
|
||||
import { getColorForFBType } from '../../../utils/freebusy.js'
|
||||
import { getFirstFreeSlot } from '../../../services/freeBusySlotService.js'
|
||||
import { getFirstFreeSlot, getBusySlots } from '../../../services/freeBusySlotService.js'
|
||||
import dateFormat from '../../../filters/dateFormat.js'
|
||||
|
||||
export default {
|
||||
|
@ -275,7 +275,7 @@ export default {
|
|||
]
|
||||
},
|
||||
formattedCurrentStart() {
|
||||
return this.currentStart.toLocaleDateString(this.lang, this.formattingOptions)
|
||||
return this.currentDate.toLocaleDateString(this.lang, this.formattingOptions)
|
||||
},
|
||||
formattedCurrentTime() {
|
||||
const options = { hour: '2-digit', minute: '2-digit', hour12: true }
|
||||
|
@ -477,12 +477,21 @@ export default {
|
|||
endSearch.setYear(this.currentDate.getFullYear())
|
||||
|
||||
try {
|
||||
const freeSlots = await getFirstFreeSlot(
|
||||
// for now search slots only in the first week days
|
||||
const endSearchDate = new Date(startSearch)
|
||||
endSearchDate.setDate(startSearch.getDate() + 7)
|
||||
const eventResults = await getBusySlots(
|
||||
this.organizer.attendeeProperty,
|
||||
this.attendees.map((a) => a.attendeeProperty),
|
||||
startSearch,
|
||||
endSearchDate,
|
||||
this.timeZoneId
|
||||
)
|
||||
|
||||
const freeSlots = getFirstFreeSlot(
|
||||
startSearch,
|
||||
endSearch,
|
||||
this.timezoneId,
|
||||
eventResults.events,
|
||||
)
|
||||
|
||||
freeSlots.forEach((slot) => {
|
||||
|
@ -506,6 +515,8 @@ export default {
|
|||
// have to make these "selected" version of the props seeing as they can't be modified directly, and they aren't updated reactively when vuex is
|
||||
this.currentStart = slot.start
|
||||
this.currentEnd = slot.end
|
||||
const clonedDate = new Date(slot.start) // so as not to modify slot.start
|
||||
this.currentDate = new Date(clonedDate.setHours(0, 0, 0, 0))
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -51,13 +51,13 @@
|
|||
<Avatar v-if="!option.isUser && option.type !== 'circle'"
|
||||
:key="option.uid"
|
||||
:url="option.avatar"
|
||||
:display-name="option.dropdownName" />
|
||||
:display-name="option.commonName" />
|
||||
|
||||
<div class="invitees-search-list-item__label">
|
||||
<div>
|
||||
{{ option.dropdownName }}
|
||||
{{ option.commonName }}
|
||||
</div>
|
||||
<div v-if="option.email !== option.dropdownName && option.type !== 'circle'">
|
||||
<div v-if="option.email !== option.commonName && option.type !== 'circle'">
|
||||
{{ option.email }}
|
||||
</div>
|
||||
<div v-if="option.type === 'circle'">
|
||||
|
@ -282,9 +282,9 @@ export default {
|
|||
email: principal.email,
|
||||
language: principal.language,
|
||||
isUser: principal.calendarUserType === 'INDIVIDUAL',
|
||||
avatar: principal.userId,
|
||||
avatar: decodeURIComponent(principal.userId),
|
||||
hasMultipleEMails: false,
|
||||
dropdownName: principal.displayname || principal.email,
|
||||
dropdownName: principal.displayname ? [principal.displayname, principal.email].join(' ') : principal.email,
|
||||
}
|
||||
})
|
||||
},
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
|
||||
-
|
||||
- @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
- @author Richard Steinmetz <richard@steinmetz.cloud>
|
||||
-
|
||||
- @license AGPL-3.0-or-later
|
||||
-
|
||||
|
@ -22,17 +23,16 @@
|
|||
|
||||
<template>
|
||||
<div class="repeat-option-set repeat-option-set--interval-freq">
|
||||
<span class="repeat-option-set__label">
|
||||
{{ repeatEveryLabel }}
|
||||
</span>
|
||||
<input v-if="!isIntervalDisabled"
|
||||
class="intervalInput"
|
||||
<NcTextField v-if="!isIntervalDisabled"
|
||||
:label="repeatEveryLabel"
|
||||
type="number"
|
||||
class="repeat-option-set__interval"
|
||||
min="1"
|
||||
max="366"
|
||||
:value="interval"
|
||||
@input="changeInterval">
|
||||
<RepeatFreqSelect :freq="frequency"
|
||||
@input="changeInterval" />
|
||||
<RepeatFreqSelect class="repeat-option-set__frequency"
|
||||
:freq="frequency"
|
||||
:count="interval"
|
||||
@change="changeFrequency" />
|
||||
</div>
|
||||
|
@ -40,11 +40,13 @@
|
|||
|
||||
<script>
|
||||
import RepeatFreqSelect from './RepeatFreqSelect.vue'
|
||||
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
|
||||
|
||||
export default {
|
||||
name: 'RepeatFreqInterval',
|
||||
components: {
|
||||
RepeatFreqSelect,
|
||||
NcTextField,
|
||||
},
|
||||
props: {
|
||||
frequency: {
|
||||
|
@ -89,3 +91,16 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.repeat-option-set {
|
||||
&__interval {
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
|
||||
&__frequency {
|
||||
min-width: unset !important;
|
||||
padding-top: 7px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -250,9 +250,3 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.resource-search__multiselect {
|
||||
padding-bottom: 5px !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -22,19 +22,22 @@
|
|||
|
||||
<template>
|
||||
<div class="resource-capacity">
|
||||
<div class="resource-capacity__input">
|
||||
<input type="number"
|
||||
min="0"
|
||||
:placeholder="placeholder"
|
||||
:value="value"
|
||||
@input.prevent.stop="changeValue">
|
||||
</div>
|
||||
<NcTextField :label="placeholder"
|
||||
type="number"
|
||||
min="0"
|
||||
:placeholder="placeholder"
|
||||
:value="value"
|
||||
@input="changeValue" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
|
||||
export default {
|
||||
name: 'ResourceSeatingCapacity',
|
||||
components: {
|
||||
NcTextField,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
|
@ -53,3 +56,9 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.resource-capacity {
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
<template functional>
|
||||
<span :aria-hidden="!props.title"
|
||||
:aria-label="props.title"
|
||||
:class="[data.class, data.staticClass]"
|
||||
class="material-design-icon icon-circle"
|
||||
role="img"
|
||||
v-bind="data.attrs"
|
||||
v-on="listeners">
|
||||
<svg :fill="props.fillColor"
|
||||
class="material-design-icon__svg"
|
||||
:width="props.size"
|
||||
:height="props.size"
|
||||
viewBox="0 0 21.33 21.33">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M10.67 1.33a9.34 9.34 0 100 18.68 9.34 9.34 0 000-18.68zM6.93 15.8a2.33 2.33 0 110-4.67 2.33 2.33 0 010 4.67zm1.4-8.87a2.33 2.33 0 114.67 0 2.33 2.33 0 01-4.67 0zm6.07 8.87a2.33 2.33 0 110-4.67 2.33 2.33 0 010 4.67z" />
|
||||
</svg>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'IconCircles',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 20,
|
||||
},
|
||||
fillColor: {
|
||||
type: String,
|
||||
default: 'currentColor',
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -20,7 +20,9 @@ registerWidget('calendar_widget', async (el, { richObjectType, richObject, acces
|
|||
store,
|
||||
propsData: {
|
||||
isWidget: true,
|
||||
referenceToken: richObject.token,
|
||||
isPublic: richObject.isPublic,
|
||||
referenceToken: richObject?.token,
|
||||
url: richObject.url,
|
||||
},
|
||||
}).$mount(el)
|
||||
return new NcCustomPickerRenderResult(vueElement.$el, vueElement)
|
||||
|
|
|
@ -33,7 +33,6 @@ import logger from '../utils/logger.js'
|
|||
* @param {AttendeeProperty[]} attendees Array of the event's attendees
|
||||
* @param {Date} start The start date and time of the event
|
||||
* @param {Date} end The end date and time of the event
|
||||
* @param timeZone Timezone of the user
|
||||
* @param timeZoneId
|
||||
* @return {Promise<>}
|
||||
*/
|
||||
|
@ -74,66 +73,72 @@ export async function getBusySlots(organizer, attendees, start, end, timeZoneId)
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the first available slot for an event using freebusy API
|
||||
* Get the first available slot for an event using the freebusy API
|
||||
*
|
||||
* @param {AttendeeProperty} organizer The organizer of the event
|
||||
* @param {AttendeeProperty[]} attendees Array of the event's attendees
|
||||
|
||||
* @param {Date} start The start date and time of the event
|
||||
* @param {Date} end The end date and time of the event
|
||||
* @param timeZoneId TimezoneId of the user
|
||||
* @return {Promise<[]>}
|
||||
* @param retrievedEvents Events found by the freebusy API
|
||||
* @return []
|
||||
*/
|
||||
export async function getFirstFreeSlot(organizer, attendees, start, end, timeZoneId) {
|
||||
export function getFirstFreeSlot(start, end, retrievedEvents) {
|
||||
let duration = getDurationInSeconds(start, end)
|
||||
if (duration === 0) {
|
||||
duration = 86400 // one day
|
||||
}
|
||||
|
||||
// for now search slots only in the first five days
|
||||
const endSearchDate = new Date(start)
|
||||
endSearchDate.setDate(start.getDate() + 5)
|
||||
const eventResults = await getBusySlots(organizer, attendees, start, endSearchDate, timeZoneId)
|
||||
endSearchDate.setDate(start.getDate() + 7)
|
||||
|
||||
if (eventResults.error) {
|
||||
return [{ error: eventResults.error }]
|
||||
if (retrievedEvents.error) {
|
||||
return [{ error: retrievedEvents.error }]
|
||||
}
|
||||
|
||||
const events = eventResults.events
|
||||
const events = sortEvents(retrievedEvents)
|
||||
|
||||
let currentCheckedTime = start
|
||||
const currentCheckedTimeEnd = new Date(currentCheckedTime)
|
||||
currentCheckedTimeEnd.setSeconds(currentCheckedTime.getSeconds() + duration)
|
||||
const foundSlots = []
|
||||
let offset = 1
|
||||
|
||||
// more than 1 suggestions is too much
|
||||
// todo: make it 5
|
||||
for (let i = 0; (i < events.length + 1 && i < 1); i++) {
|
||||
if (new Date(events[0]?.start) < currentCheckedTime) {
|
||||
offset = 0
|
||||
}
|
||||
|
||||
for (let i = 0; i < events.length + offset && i < 5; i++) {
|
||||
foundSlots[i] = checkTimes(currentCheckedTime, duration, events)
|
||||
|
||||
if (foundSlots[i].nextEvent !== undefined && foundSlots[i].nextEvent !== null) currentCheckedTime = new Date(foundSlots[i].nextEvent.end)
|
||||
if (foundSlots[i].nextEvent !== undefined && foundSlots[i].nextEvent !== null) {
|
||||
currentCheckedTime = new Date(foundSlots[i].nextEvent.end)
|
||||
}
|
||||
// avoid repetitions caused by events blocking at first iteration of currentCheckedTime
|
||||
if (foundSlots[i]?.start === foundSlots[i - 1]?.start) {
|
||||
foundSlots.pop()
|
||||
if (foundSlots[i]?.start === foundSlots[i - 1]?.start && foundSlots[i] !== undefined) {
|
||||
foundSlots[i] = {}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
foundSlots.forEach((slot, index) => {
|
||||
const roundedTime = roundTime(slot.start, slot.end, slot.blockingEvent, duration)
|
||||
const roundedSlots = []
|
||||
|
||||
foundSlots[index].start = roundedTime.start
|
||||
foundSlots[index].end = roundedTime.end
|
||||
// not needed anymore
|
||||
foundSlots[index].nextEvent = undefined
|
||||
foundSlots.forEach((slot) => {
|
||||
const roundedTime = roundTime(slot.start, slot.end, slot.blockingEvent, slot.nextEvent, duration)
|
||||
|
||||
if (roundedTime !== null && roundedTime.start < endSearchDate) {
|
||||
roundedSlots.push({
|
||||
start: roundedTime.start,
|
||||
end: roundedTime.end,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return foundSlots
|
||||
return roundedSlots
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param start
|
||||
* @param end
|
||||
* @return {number}
|
||||
*/
|
||||
function getDurationInSeconds(start, end) {
|
||||
// convert dates to UTC to account for daylight saving time
|
||||
|
@ -150,9 +155,11 @@ function getDurationInSeconds(start, end) {
|
|||
* @param currentCheckedTime
|
||||
* @param currentCheckedTimeEnd
|
||||
* @param blockingEvent
|
||||
* @param nextEvent
|
||||
* @param duration
|
||||
*/
|
||||
function roundTime(currentCheckedTime, currentCheckedTimeEnd, blockingEvent, duration) {
|
||||
function roundTime(currentCheckedTime, currentCheckedTimeEnd, blockingEvent, nextEvent, duration) {
|
||||
if (currentCheckedTime === null) return null
|
||||
if (!blockingEvent) return { start: currentCheckedTime, end: currentCheckedTimeEnd }
|
||||
|
||||
// make sure that difference between currentCheckedTime and blockingEvent.end is at least 15 minutes
|
||||
|
@ -177,6 +184,11 @@ function roundTime(currentCheckedTime, currentCheckedTimeEnd, blockingEvent, dur
|
|||
currentCheckedTimeEnd = new Date(currentCheckedTime)
|
||||
currentCheckedTimeEnd.setSeconds(currentCheckedTime.getSeconds() + duration)
|
||||
|
||||
// if the rounding of the event doesn't conflict with the start of the next one
|
||||
if (currentCheckedTimeEnd > new Date(nextEvent?.start)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return { start: currentCheckedTime, end: currentCheckedTimeEnd }
|
||||
}
|
||||
|
||||
|
@ -245,3 +257,19 @@ function checkTimes(currentCheckedTime, duration, events) {
|
|||
|
||||
return { start: currentCheckedTime, end: currentCheckedTimeEnd, nextEvent, blockingEvent }
|
||||
}
|
||||
|
||||
// make a function that sorts a list of objects by the "start" property
|
||||
function sortEvents(events) {
|
||||
// remove events that have the same start and end time, if not done causes problems
|
||||
const mappedEvents = new Map()
|
||||
|
||||
for (const obj of events) {
|
||||
const key = obj.start.toString() + obj.end.toString()
|
||||
|
||||
if (!mappedEvents.has(key)) {
|
||||
mappedEvents.set(key, obj)
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(mappedEvents.values()).sort((a, b) => new Date(a.start) - new Date(b.start))
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import '@nextcloud/dialogs/dist/index.css'
|
||||
import '@nextcloud/dialogs/style.css'
|
||||
|
||||
import {
|
||||
NcAvatar as Avatar,
|
||||
|
|
|
@ -22,11 +22,12 @@
|
|||
|
||||
<template>
|
||||
<div v-if="isWidget" class="calendar-Widget">
|
||||
<EmbedTopNavigation :is-widget="true" />
|
||||
<EmbedTopNavigation v-if="!showEmptyCalendarScreen" :is-widget="true" />
|
||||
|
||||
<CalendarGrid v-if="!showEmptyCalendarScreen"
|
||||
ref="calendarGridWidget"
|
||||
:is-widget="isWidget"
|
||||
:url="url"
|
||||
:is-authenticated-user="isAuthenticatedUser" />
|
||||
<EmptyCalendar v-else />
|
||||
|
||||
|
@ -115,7 +116,7 @@ import { loadState } from '@nextcloud/initial-state'
|
|||
import {
|
||||
showWarning,
|
||||
} from '@nextcloud/dialogs'
|
||||
import '@nextcloud/dialogs/dist/index.css'
|
||||
import '@nextcloud/dialogs/style.css'
|
||||
import Trashbin from '../components/AppNavigation/CalendarList/Trashbin.vue'
|
||||
import AppointmentConfigList from '../components/AppNavigation/AppointmentConfigList.vue'
|
||||
|
||||
|
@ -139,14 +140,26 @@ export default {
|
|||
EditSimple,
|
||||
},
|
||||
props: {
|
||||
// Is the calendar in a widget ?
|
||||
isWidget: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// The reference token for the widget for public share calendars
|
||||
referenceToken: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
// Is public share ?
|
||||
isPublic: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
// Url of private calendar
|
||||
url: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -263,7 +276,7 @@ export default {
|
|||
})
|
||||
this.$store.dispatch('initializeCalendarJsConfig')
|
||||
|
||||
if (this.$route?.name.startsWith('Public') || this.$route?.name.startsWith('Embed') || this.isWidget) {
|
||||
if (this.$route?.name.startsWith('Public') || this.$route?.name.startsWith('Embed') || this.isPublic) {
|
||||
await initializeClientForPublicView()
|
||||
const tokens = this.isWidget ? [this.referenceToken] : this.$route.params.tokens.split('-')
|
||||
const calendars = await this.$store.dispatch('getPublicCalendars', { tokens })
|
||||
|
|
|
@ -719,5 +719,10 @@ export default {
|
|||
// Close button should be aligned with calendar picker (header)
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.empty-content {
|
||||
height: 100vh;
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* @copyright 2024 Grigory Vodyanov <scratchx@gmx.com>
|
||||
*
|
||||
* @author 2024 Grigory Vodyanov <scratchx@gmx.com>
|
||||
*
|
||||
* @license AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import { getFirstFreeSlot } from "../../../../src/services/freeBusySlotService.js";
|
||||
|
||||
describe('services/freeBusySlotService test suite', () => {
|
||||
|
||||
it('should return the first rounded slot after blocking event end', () => {
|
||||
const events = [
|
||||
{
|
||||
start: '2024-01-01T09:00:00Z',
|
||||
end: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
let start = new Date('2024-01-01T08:30:00Z')
|
||||
let end = new Date('2024-01-01T09:30:00Z')
|
||||
|
||||
const result = getFirstFreeSlot(start, end, events)
|
||||
|
||||
expect(result[0].start).toEqual(new Date('2024-01-01T10:30:00Z'))
|
||||
expect(result[0].end).toEqual(new Date('2024-01-01T11:30:00Z'))
|
||||
})
|
||||
|
||||
it('should return the same amount of suggested slots as events plus one if first blocking event starts after searched time', () => {
|
||||
// First blocking event starts after the searched time
|
||||
const events = [
|
||||
{
|
||||
start: '2024-01-01T09:00:00Z',
|
||||
end: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
{
|
||||
start: '2024-01-01T12:00:00Z',
|
||||
end: '2024-01-01T14:00:00Z',
|
||||
},
|
||||
{
|
||||
start: '2024-01-02T18:00:00Z',
|
||||
end: '2024-01-02T19:00:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
let start = new Date('2024-01-01T08:00:00Z')
|
||||
let end = new Date('2024-01-01T08:45:00Z')
|
||||
|
||||
const result = getFirstFreeSlot(start, end, events)
|
||||
|
||||
expect(result.length).toEqual(events.length + 1)
|
||||
|
||||
expect(result[3].start).toEqual(new Date('2024-01-02T19:30:00Z'))
|
||||
expect(result[3].end).toEqual(new Date('2024-01-02T20:15:00Z'))
|
||||
})
|
||||
|
||||
it('should return the same amount of suggested slots as events if first blocking event conflicts with searched time', () => {
|
||||
// First blocking event starts before the searched time
|
||||
const events = [
|
||||
{
|
||||
start: '2023-12-31T09:00:00Z',
|
||||
end: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
{
|
||||
start: '2024-01-01T12:00:00Z',
|
||||
end: '2024-01-01T14:00:00Z',
|
||||
},
|
||||
{
|
||||
start: '2024-01-02T18:00:00Z',
|
||||
end: '2024-01-02T19:00:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
let start = new Date('2024-01-01T08:00:00Z')
|
||||
let end = new Date('2024-01-01T08:45:00Z')
|
||||
|
||||
const result = getFirstFreeSlot(start, end, events)
|
||||
|
||||
expect(result.length).toEqual(events.length)
|
||||
|
||||
expect(result[2].start).toEqual(new Date('2024-01-02T19:30:00Z'))
|
||||
expect(result[2].end).toEqual(new Date('2024-01-02T20:15:00Z'))
|
||||
})
|
||||
|
||||
it('should not give slots between events if the difference is smaller than the searched time duration', () => {
|
||||
// First blocking event starts before the searched time
|
||||
const events = [
|
||||
{
|
||||
start: '2024-01-01T12:00:00Z',
|
||||
end: '2024-01-01T14:00:00Z',
|
||||
},
|
||||
{
|
||||
start: '2024-01-01T15:30:00Z',
|
||||
end: '2024-01-01T16:00:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
let start = new Date('2024-01-01T11:00:00Z')
|
||||
let end = new Date('2024-01-01T12:45:00Z')
|
||||
|
||||
const result = getFirstFreeSlot(start, end, events)
|
||||
|
||||
expect(result[0].start).toEqual(new Date('2024-01-01T16:30:00Z'))
|
||||
})
|
||||
|
||||
})
|
|
@ -25,6 +25,7 @@ declare(strict_types=1);
|
|||
namespace OCA\Calendar\Controller;
|
||||
|
||||
use ChristophWurst\Nextcloud\Testing\TestCase;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
|
@ -46,7 +47,6 @@ use OCP\IUser;
|
|||
use OCP\Mail\IMailer;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Safe\DateTimeImmutable;
|
||||
|
||||
class BookingControllerTest extends TestCase {
|
||||
/** @var string */
|
||||
|
|
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace OCA\Calendar\Dashboard;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use OCA\Calendar\Service\JSDataService;
|
||||
use OCA\DAV\CalDAV\CalendarImpl;
|
||||
use OCP\AppFramework\Services\IInitialState;
|
||||
|
@ -34,7 +35,6 @@ use OCP\IDateTimeFormatter;
|
|||
use OCP\IL10N;
|
||||
use OCP\IURLGenerator;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Safe\DateTimeImmutable;
|
||||
use Test\TestCase;
|
||||
|
||||
class CalendarWidgetTest extends TestCase {
|
||||
|
|
|
@ -27,6 +27,7 @@ declare(strict_types=1);
|
|||
namespace OCA\Calendar\Tests\Unit\Service\Appointments;
|
||||
|
||||
use ChristophWurst\Nextcloud\Testing\TestCase;
|
||||
use DateTimeImmutable;
|
||||
use Exception;
|
||||
use OCA\Calendar\Db\AppointmentConfig;
|
||||
use OCA\Calendar\Db\Booking;
|
||||
|
@ -47,7 +48,6 @@ use OCP\IUser;
|
|||
use OCP\Security\ISecureRandom;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Safe\DateTimeImmutable;
|
||||
|
||||
class BookingServiceTest extends TestCase {
|
||||
/** @var AvailabilityGenerator|MockObject */
|
||||
|
|
Loading…
Reference in New Issue