mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-10-12 15:04:04 +00:00
- Listenansicht hoehe der Tabelle auf 100%
- Listenansicht "status" Delete entfernt, Button gelassen - Tags ohne Dialog & Popaus aus dem Kontextmenue entfernt - Einstellung Prioraum verwenden Raumauswahl anzeigen als Dropdown - Sortierung der Raeume im Event - Reservierung anzeigen wenn STG Filter gesetzt ist - Course Picker kuerzen von Events erst nach Confirm - Fehlende Phrasen hinzugefuegt
This commit is contained in:
@@ -39,8 +39,7 @@ class Config extends FHCAPI_Controller
|
||||
'ignore_zeitsperre',
|
||||
'ignore_resources_collisions',
|
||||
'roomless_planning',
|
||||
'priority_room_planning',
|
||||
'dialog_room_planning'
|
||||
'room_planning',
|
||||
);
|
||||
$result = $this->_ci->VariableModel->getVariables(getAuthUID(), $var_array);
|
||||
|
||||
@@ -49,7 +48,6 @@ class Config extends FHCAPI_Controller
|
||||
"type" => "checkbox",
|
||||
"label" => $this->p->t('ui', 'ignore_kollision'),
|
||||
"value" => ($data['ignore_kollision'] ?? 'false') === 'true'
|
||||
|
||||
];
|
||||
|
||||
$config['kollision_student'] = [
|
||||
@@ -83,19 +81,16 @@ class Config extends FHCAPI_Controller
|
||||
"value" => ($data['roomless_planning'] ?? 'false') === 'true'
|
||||
];
|
||||
|
||||
$config['priority_room_planning'] = [
|
||||
"type" => "checkbox",
|
||||
"label" => $this->p->t('ui', 'priority_room_planning'),
|
||||
"value" => ($data['priority_room_planning'] ?? 'false') === 'true'
|
||||
$config['room_planning'] = [
|
||||
"type" => "select",
|
||||
"label" => $this->p->t('ui', 'room_planning'),
|
||||
"value" => $data['room_planning'] ?? "dialog_room_planning",
|
||||
"options" => [
|
||||
'dialog_room_planning' => $this->p->t('ui', 'dialog_room_planning'),
|
||||
'priority_room_planning' => $this->p->t('ui', 'priority_room_planning'),
|
||||
],
|
||||
];
|
||||
|
||||
$config['dialog_room_planning'] = [
|
||||
"type" => "checkbox",
|
||||
"label" => $this->p->t('ui', 'dialog_room_planning'),
|
||||
"value" => ($data['dialog_room_planning'] ?? 'false') === 'true'
|
||||
];
|
||||
|
||||
|
||||
$this->terminateWithSuccess($config);
|
||||
}
|
||||
public function getHeader()
|
||||
@@ -121,6 +116,8 @@ class Config extends FHCAPI_Controller
|
||||
|
||||
public function set()
|
||||
{
|
||||
$this->_ci->load->library('form_validation');
|
||||
|
||||
$configs = array(
|
||||
'ignore_kollision',
|
||||
'kollision_student',
|
||||
@@ -128,10 +125,18 @@ class Config extends FHCAPI_Controller
|
||||
'ignore_zeitsperre',
|
||||
'ignore_resources_collisions',
|
||||
'roomless_planning',
|
||||
'priority_room_planning',
|
||||
'dialog_room_planning'
|
||||
);
|
||||
|
||||
$this->form_validation->set_rules(
|
||||
'room_planning',
|
||||
$this->p->t('ui', 'room_planning'),
|
||||
'required|in_list[dialog_room_planning,priority_room_planning]'
|
||||
);
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
|
||||
foreach ($configs as $config)
|
||||
{
|
||||
$this->_ci->VariableModel->setVariable(
|
||||
@@ -141,6 +146,12 @@ class Config extends FHCAPI_Controller
|
||||
);
|
||||
}
|
||||
|
||||
$this->VariableModel->setVariable(
|
||||
getAuthUID(),
|
||||
'room_planning',
|
||||
$this->input->post('room_planning')
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
|
||||
|
||||
@@ -457,7 +457,8 @@ class Kalender extends FHCAPI_Controller
|
||||
$ort_kurzbz = $this->_ci->input->post('ort_kurzbz', TRUE);
|
||||
$start_date = $this->_ci->input->post('start_date', TRUE);
|
||||
$end_date = $this->_ci->input->post('end_date', TRUE);
|
||||
$result = $this->_ci->kalenderlib->addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz);
|
||||
$first_run = $this->_ci->input->post('first_run', TRUE) ?? true;
|
||||
$result = $this->_ci->kalenderlib->addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz, $first_run);
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError(getError($result));
|
||||
|
||||
@@ -138,6 +138,12 @@ class Reservierung extends FHCAPI_Controller
|
||||
return in_array($gruppe->studiengang_kz, $stg_berechtigungen);
|
||||
});
|
||||
|
||||
|
||||
usort($gefilterte_gruppen, function ($a, $b)
|
||||
{
|
||||
return [(int) $a->semester, $a->gruppe_kurzbz] <=> [(int) $b->semester, $b->gruppe_kurzbz];
|
||||
});
|
||||
|
||||
$this->terminateWithSuccess($gefilterte_gruppen);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ class KalenderLib
|
||||
public function getForRaumvorschlag($start_date, $end_date, $lektor_uids = [], $gruppen_kurzbz = [], $lehrverband_gruppen = [])
|
||||
{
|
||||
$start_date = date('Y-m-d', strtotime($start_date));
|
||||
$end_date = date('Y-m-d', strtotime($end_date . ' +1 day'));
|
||||
|
||||
$this->_buildBasePlanQuery();
|
||||
|
||||
@@ -169,23 +168,38 @@ class KalenderLib
|
||||
if (!is_null($studiengaenge))
|
||||
{
|
||||
$db = $this->_ci->KalenderModel->db;
|
||||
$or_conditions = array();
|
||||
$lv_or_conditions = array();
|
||||
$teilnehmer_or_conditions = array();
|
||||
|
||||
foreach ($studiengaenge as $studiengang)
|
||||
{
|
||||
$conditions = array();
|
||||
$conditions[] = 'filter_lv.studiengang_kz = ' . $db->escape($studiengang['stg_kz']);
|
||||
$stg_kz = $db->escape($studiengang['stg_kz']);
|
||||
|
||||
$lv_conditions = array('filter_lv.studiengang_kz = '. $stg_kz);
|
||||
$teilnehmer_conditions = array('COALESCE(filter_teilnehmer.studiengang_kz, filter_grp.studiengang_kz) = ' .$stg_kz);
|
||||
|
||||
|
||||
if (isset($studiengang['semester']))
|
||||
$conditions[] = 'filter_lv.semester = ' . $db->escape($studiengang['semester']);
|
||||
{
|
||||
$semester = $db->escape($studiengang['semester']);
|
||||
|
||||
$lv_conditions[] = 'filter_lv.semester = ' . $semester;
|
||||
$teilnehmer_conditions[] = 'COALESCE(filter_teilnehmer.semester, filter_grp.semester) = ' . $semester;
|
||||
}
|
||||
|
||||
if (isset($studiengang['orgform_kurzbz']))
|
||||
$conditions[] = 'filter_lv.orgform_kurzbz = ' . $db->escape($studiengang['orgform_kurzbz']);
|
||||
{
|
||||
$orgform_kurzbz = $db->escape($studiengang['orgform_kurzbz']);
|
||||
$lv_conditions[] = 'filter_lv.orgform_kurzbz = ' . $orgform_kurzbz;
|
||||
$teilnehmer_conditions[] = 'COALESCE(filter_lehrverband.orgform_kurzbz, filter_grp.orgform_kurzbz) = ' . $orgform_kurzbz;
|
||||
}
|
||||
|
||||
$or_conditions[] = '(' . implode(' AND ', $conditions) . ')';
|
||||
$lv_or_conditions[] = '(' . implode(' AND ', $lv_conditions) . ')';
|
||||
$teilnehmer_or_conditions[] = '(' . implode(' AND ', $teilnehmer_conditions) . ')';
|
||||
}
|
||||
|
||||
$or_block = implode(' OR ', $or_conditions);
|
||||
$lv_or_block = implode(' OR ', $lv_or_conditions);
|
||||
$teilnehmer_or_block = implode(' OR ', $teilnehmer_or_conditions);
|
||||
|
||||
$this->_ci->KalenderModel->db->where(
|
||||
"(EXISTS (
|
||||
@@ -194,8 +208,20 @@ class KalenderLib
|
||||
JOIN lehre.tbl_lehreinheit filter_le ON filter_le.lehreinheit_id = filter_kl.lehreinheit_id
|
||||
JOIN lehre.tbl_lehrveranstaltung filter_lv ON filter_lv.lehrveranstaltung_id = filter_le.lehrveranstaltung_id
|
||||
WHERE filter_kl.kalender_id = tbl_kalender.kalender_id
|
||||
AND ($or_block)
|
||||
))"
|
||||
AND ($lv_or_block)
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM lehre.tbl_kalender_event_teilnehmer filter_teilnehmer
|
||||
LEFT JOIN public.tbl_gruppe filter_grp ON filter_grp.gruppe_kurzbz = filter_teilnehmer.gruppe_kurzbz
|
||||
LEFT JOIN public.tbl_lehrverband filter_lehrverband ON filter_lehrverband.studiengang_kz = filter_teilnehmer.studiengang_kz
|
||||
AND filter_lehrverband.semester = filter_teilnehmer.semester
|
||||
AND TRIM(COALESCE(filter_teilnehmer.verband::text, '')) = TRIM(filter_lehrverband.verband::text)
|
||||
AND TRIM(COALESCE(filter_teilnehmer.gruppe::text, '')) = TRIM(filter_lehrverband.gruppe::text)
|
||||
WHERE filter_teilnehmer.kalender_id = tbl_kalender.kalender_id
|
||||
AND (filter_teilnehmer.gruppe_kurzbz IS NOT NULL OR filter_teilnehmer.studiengang_kz IS NOT NULL)
|
||||
AND ($teilnehmer_or_block)
|
||||
))", null, false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -537,6 +563,11 @@ class KalenderLib
|
||||
'false'
|
||||
);
|
||||
|
||||
$this->_ci->StundeModel->addLimit(1);
|
||||
$this->_ci->StundeModel->addOrder('stunde', 'DESC');
|
||||
$letzte_stunde_result = $this->_ci->StundeModel->load();
|
||||
|
||||
$letzte_stunde = getData($letzte_stunde_result)[0];
|
||||
while ($rest > 0 && new DateTime($current_date) < $ende)
|
||||
{
|
||||
$max_skip = 52;
|
||||
@@ -564,12 +595,7 @@ class KalenderLib
|
||||
|
||||
if (!hasData($end_stunde_result))
|
||||
{
|
||||
$errors[] = [
|
||||
'datum' => $current_date,
|
||||
'message' => 'Endzeit entspricht keinem gültigen Raster',
|
||||
];
|
||||
$current_date = $this->_addWeeks($current_date, $wochenrythmus);
|
||||
continue;
|
||||
$current_block = $letzte_stunde->stunde - $start_stunde_nr + 1;
|
||||
}
|
||||
|
||||
$end_time = getData($end_stunde_result)[0]->ende;
|
||||
@@ -655,7 +681,7 @@ class KalenderLib
|
||||
}
|
||||
|
||||
|
||||
public function addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz)
|
||||
public function addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz, $first_run = false)
|
||||
{
|
||||
if (!$this->_checkPermission((array)$lehreinheit_id))
|
||||
{
|
||||
@@ -674,24 +700,45 @@ class KalenderLib
|
||||
|
||||
$raum_vorschlaege = $this->_ci->raumvorschlaglib->getVorschlaegeByLehreinheit($lehreinheit_id, $start_date, $end_date);
|
||||
|
||||
if (($this->_ci->variablelib->getVar('dialog_room_planning') ?? 'false') === 'true')
|
||||
$room_planning = $this->_ci->variablelib->getVar('room_planning') ?? 'priority_room_planning';
|
||||
if ($first_run || (($this->_ci->variablelib->getVar('roomless_planning') ?? 'false') !== 'true'))
|
||||
{
|
||||
return success([
|
||||
'needs_room_selection' => true,
|
||||
'raum_vorschlaege' => is_array($raum_vorschlaege) ? $raum_vorschlaege : [],
|
||||
]);
|
||||
}
|
||||
if ($room_planning === 'dialog_room_planning')
|
||||
{
|
||||
if (!$first_run)
|
||||
{
|
||||
return error([
|
||||
'message' => $this->_ci->phraseslib->t('ui', 'roomless_planning_error'),
|
||||
'errorCode' => 'roomless_planning_error'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return success([
|
||||
'needs_room_selection' => true,
|
||||
'raum_vorschlaege' => is_array($raum_vorschlaege) ? $raum_vorschlaege : [],
|
||||
]);
|
||||
}
|
||||
}
|
||||
else if ($room_planning === 'priority_room_planning')
|
||||
{
|
||||
$ort_kurzbz = !empty($raum_vorschlaege[0]['ort_kurzbz']) ? $raum_vorschlaege[0]['ort_kurzbz'] : null;
|
||||
|
||||
if (($this->_ci->variablelib->getVar('priority_room_planning') ?? 'false') === 'true')
|
||||
{
|
||||
$ort_kurzbz = (is_array($raum_vorschlaege)) ? $raum_vorschlaege[0]['ort_kurzbz'] : null;
|
||||
}
|
||||
else if (!(($this->_ci->variablelib->getVar('roomless_planning') ?? 'false') === 'true'))
|
||||
{
|
||||
return error([
|
||||
'message' => $this->_ci->phraseslib->t('ui', 'roomless_planning_error'),
|
||||
'errorCode' => 'roomless_planning_error'
|
||||
]);
|
||||
if (is_null($ort_kurzbz) && !(($this->_ci->variablelib->getVar('roomless_planning') ?? 'false') === 'true'))
|
||||
{
|
||||
return error([
|
||||
'message' => $this->_ci->phraseslib->t('ui', 'roomless_prio_planning_error'),
|
||||
'errorCode' => 'roomless_planning_error'
|
||||
]);
|
||||
}
|
||||
}
|
||||
else if (!(($this->_ci->variablelib->getVar('roomless_planning') ?? 'false') === 'true'))
|
||||
{
|
||||
return error([
|
||||
'message' => $this->_ci->phraseslib->t('ui', 'roomless_planning_error'),
|
||||
'errorCode' => 'roomless_planning_error'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -901,7 +948,7 @@ class KalenderLib
|
||||
if (!empty($errors)) {
|
||||
return error($errors);
|
||||
}
|
||||
|
||||
|
||||
$this->_ci->db->trans_start();
|
||||
|
||||
$allowedResourceIDs = array_filter(array_map(
|
||||
@@ -984,7 +1031,7 @@ class KalenderLib
|
||||
|
||||
if (!is_null($orte))
|
||||
{
|
||||
$kalender_entry->ort_kurbz = !isEmptyArray($orte['ort_kurzbz'] ?? null) ? (array) $orte['ort_kurzbz'] : $kalender_entry->ort_kurzbz;
|
||||
$kalender_entry->ort_kurzbz = !isEmptyArray($orte['ort_kurzbz'] ?? null) ? (array) $orte['ort_kurzbz'] : $kalender_entry->ort_kurzbz;
|
||||
$kalender_entry->location = array_key_exists('location', $orte) && !is_null($orte['location']) ? $orte['location'] : $kalender_entry->location;
|
||||
}
|
||||
$kalender_entry->von = $start_time ?? $kalender_entry->von;
|
||||
@@ -1657,7 +1704,7 @@ class KalenderLib
|
||||
|
||||
if ($row->verband_grp)
|
||||
{
|
||||
if (!in_array($row->teilnehmerg_grp, array_column($events[$id]->teilnehmer_gruppe, 'gruppe_kurzbz')))
|
||||
if (!in_array($row->verband_grp, array_column($events[$id]->teilnehmer_gruppe, 'gruppe_kurzbz')))
|
||||
{
|
||||
$events[$id]->teilnehmer_gruppe[] = [
|
||||
'gruppe_kurzbz' => $row->verband_grp,
|
||||
@@ -1718,6 +1765,11 @@ class KalenderLib
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($events as $event)
|
||||
{
|
||||
usort($event->ort_kurzbz, 'strnatcasecmp');
|
||||
}
|
||||
|
||||
return array_values($events);
|
||||
}
|
||||
|
||||
@@ -1753,6 +1805,8 @@ class KalenderLib
|
||||
|
||||
if (hasData($ferien_result))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function _insertKalenderEventRaw($start_date, $end_date, $lehreinheit_id, $ort_kurzbz)
|
||||
@@ -2140,7 +2194,7 @@ class KalenderLib
|
||||
|
||||
$lehreinheit = $this->_ci->LehreinheitModel->load();
|
||||
if (!hasData($lehreinheit))
|
||||
return error('Lehreinheit nicht gefunden');
|
||||
return false;
|
||||
|
||||
$studiengaenge = array_unique(array_column(getData($lehreinheit), 'studiengang_kz'));
|
||||
|
||||
|
||||
@@ -96,11 +96,11 @@ export default {
|
||||
params: { kalender_id}
|
||||
};
|
||||
},
|
||||
addKalenderEvent(lehreinheit_id, ort_kurzbz, start_date, end_date) {
|
||||
addKalenderEvent(lehreinheit_id, ort_kurzbz, start_date, end_date, first_run) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Kalender/addKalenderEvent',
|
||||
params: { lehreinheit_id, ort_kurzbz, start_date, end_date}
|
||||
params: { lehreinheit_id, ort_kurzbz, start_date, end_date, first_run}
|
||||
};
|
||||
},
|
||||
calculateMultiWeekPlan(lehreinheit_id, ort_kurzbz, start_date, end_date) {
|
||||
|
||||
@@ -383,12 +383,12 @@ export default {
|
||||
if (accumulated >= duration)
|
||||
{
|
||||
const overflow = accumulated.minus(duration);
|
||||
return blockEnd.minus(overflow);
|
||||
return {end: blockEnd.minus(overflow), shortened: false}
|
||||
}
|
||||
}
|
||||
|
||||
const lastBlock = blocks[blocks.length - 1];
|
||||
return dropStart.startOf('day').plus(lastBlock.end);
|
||||
return {end: dropStart.startOf('day').plus(lastBlock.end), shortened: true}
|
||||
},
|
||||
|
||||
onDropEvent(evt, items, date)
|
||||
@@ -398,7 +398,7 @@ export default {
|
||||
else
|
||||
this.onDropFree(evt, items, date)
|
||||
},
|
||||
onDropSnap(evt, items, date, part) {
|
||||
async onDropSnap(evt, items, date, part) {
|
||||
let obj = items;
|
||||
if (!obj?.orig) return;
|
||||
|
||||
@@ -419,7 +419,13 @@ export default {
|
||||
const dropStart = snappedPart ? dropDay.plus(snappedPart.start) : grabTime;
|
||||
|
||||
let nettoDuration = this._getNettoDurationForDrop(obj);
|
||||
let dropEnd = this.calculateDropEnd(dropStart, nettoDuration);
|
||||
|
||||
let {end: dropEnd, shortened} = this.calculateDropEnd(dropStart, nettoDuration);
|
||||
|
||||
if (shortened && await this.$fhcAlert.confirm({message: 'Wird auf ' + dropEnd.toFormat('HH:mm') + ' gekürzt. Fortfahren?'}) === false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.onDrop?.({
|
||||
item: [obj],
|
||||
@@ -449,7 +455,7 @@ export default {
|
||||
|
||||
return luxon.Duration.fromObject({ minutes: 45 });
|
||||
},
|
||||
onDropFree(evt, items, date)
|
||||
async onDropFree(evt, items, date)
|
||||
{
|
||||
let obj = items;
|
||||
if (!obj?.orig)
|
||||
@@ -459,8 +465,12 @@ export default {
|
||||
const dropStart = luxon.DateTime.fromMillis(timestamp);
|
||||
|
||||
let nettoDuration = this._getNettoDurationForDrop(obj);
|
||||
let dropEnd = this.calculateDropEnd(dropStart, nettoDuration);
|
||||
let {end: dropEnd, shortened} = this.calculateDropEnd(dropStart, nettoDuration);
|
||||
|
||||
if (shortened && await this.$fhcAlert.confirm({message: 'Wird auf ' + dropEnd.toFormat('HH:mm') + ' gekürzt. Fortfahren?'}) === false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.onDrop?.({
|
||||
item: [obj],
|
||||
start: dropStart.toISO(),
|
||||
|
||||
@@ -48,7 +48,8 @@ export default {
|
||||
this.$emit('update:range', this.range);
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<div
|
||||
class="fhc-calendar-mode-month flex-grow-1 position-relative">
|
||||
<table-view ref="view" v-bind="$attrs" :day="focusDate" :end="focusEnd">
|
||||
<template v-slot="slot"><slot v-bind="slot" mode="week" /></template>
|
||||
</table-view>
|
||||
|
||||
@@ -85,6 +85,7 @@ export default {
|
||||
layout: 'fitDataStretch',
|
||||
placeholder: "Keine Daten verfügbar",
|
||||
persistenceID: "2026_09_29_table_view_v1",
|
||||
height: '100%',
|
||||
data: this.preparedEvents,
|
||||
columns: [
|
||||
{
|
||||
@@ -132,11 +133,10 @@ export default {
|
||||
let semester = cell.getRow().getData().le_studiensemester_kurzbz.toLowerCase();
|
||||
let base_url = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
||||
|
||||
//TODO (david) abhängig von der LVVerwaltung
|
||||
/*return value.map(lehreinheit => {
|
||||
return value.map(lehreinheit => {
|
||||
let url = `${base_url}/LVVerwaltung/stdsem/${semester}/le/${lehreinheit}`;
|
||||
return `<a href="${url}" target="_blank">${lehreinheit}</a>`;
|
||||
}).join(', ');*/
|
||||
}).join(', ');
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -352,7 +352,7 @@ export default {
|
||||
},
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="fhc-calendar-mode-table-view h-100 overflow-auto">
|
||||
<div class="fhc-calendar-mode-table-view position-absolute top-0 start-0 w-100 h-100 d-flex flex-column">
|
||||
<core-filter-cmpt
|
||||
ref="tableViewTable"
|
||||
:tabulator-options="tabulatorOptions"
|
||||
@@ -380,7 +380,6 @@ export default {
|
||||
<div class="d-flex gap-2 align-items-baseline">
|
||||
<select v-model="actionSelect" class="form-select">
|
||||
<option selected disabled value="">Status setzen</option>
|
||||
<option value="delete">Löschen</option>
|
||||
<option value="toLecturer">Freischalten für Voransicht</option>
|
||||
<option value="toStudent">Freischalten für Live</option>
|
||||
</select>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import TagsAssignmentModal from "../../TagsAssignmentModal.js";
|
||||
import ApiKalender from '../../../../api/factory/tempus/kalender.js';
|
||||
import FormInput from "../../../Form/Input.js";
|
||||
import RaumauswahlModal from '../../RaumauswahlModal.js';
|
||||
import CoreTag from '../../../../components/Tag/Tag.js';
|
||||
import ApiTempusTag from "../../../../api/factory/tempus/tag.js";
|
||||
import { idTagFormatter } from "../../../Tag/tagFormatter.js";
|
||||
|
||||
export default {
|
||||
components:{
|
||||
FormInput,
|
||||
TagsAssignmentModal,
|
||||
RaumauswahlModal
|
||||
RaumauswahlModal,
|
||||
CoreTag
|
||||
},
|
||||
props:{
|
||||
event: {
|
||||
@@ -46,7 +48,8 @@ export default {
|
||||
anzahl: '',
|
||||
anzahlSchwund: '',
|
||||
mailto: '',
|
||||
zeitwunschMap: {}
|
||||
zeitwunschMap: {},
|
||||
tagEndpoint: ApiTempusTag,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@@ -54,9 +57,17 @@ export default {
|
||||
if (this.editStundeBis !== null && this.editStundeBis < newVal)
|
||||
this.editStundeBis = newVal;
|
||||
},
|
||||
tags: {
|
||||
handler() {
|
||||
this.renderTags();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
tagValues() {
|
||||
return this.event.eindeutige_kalender_gruppen_id ? [this.event.eindeutige_kalender_gruppen_id] : [];
|
||||
},
|
||||
lektorenLinks: function () {
|
||||
if (!this.event || !Array.isArray(this.event.lektor) || !this.event.lektor.length) return "a";
|
||||
|
||||
@@ -66,14 +77,8 @@ export default {
|
||||
})
|
||||
return lektorenLinks;
|
||||
},
|
||||
getOrtContentLink: function () {
|
||||
if (!this.event || !this.event.ort_content_id) return "a";
|
||||
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/CisVue/Cms/content/${this.event.ort_content_id}`
|
||||
},
|
||||
lvLinks()
|
||||
{
|
||||
//TODO (david) abhängig von der LVVerwaltung
|
||||
let semester = this.event.le_studiensemester_kurzbz.toLowerCase();
|
||||
let base_url = FHC_JS_DATA_STORAGE_OBJECT.app_root;
|
||||
let ci_url = base_url + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
||||
@@ -82,26 +87,22 @@ export default {
|
||||
lvverwaltung: {},
|
||||
vilesci: {},
|
||||
}
|
||||
/*this.event.lehrveranstaltung_infos.forEach(lehrveranstaltung => {
|
||||
this.event.lehrveranstaltung_infos.forEach(lehrveranstaltung => {
|
||||
lvLinks.lvverwaltung[lehrveranstaltung.lehrveranstaltung_id] = `${ci_url}/LVVerwaltung/stdsem/${semester}/lv/${lehrveranstaltung.lehrveranstaltung_id}`;
|
||||
lvLinks.vilesci[lehrveranstaltung.lehrveranstaltung_id] = `${base_url}vilesci/lehre/lehrveranstaltung_details.php?lv_id=${lehrveranstaltung.lehrveranstaltung_id}`;
|
||||
})*/
|
||||
})
|
||||
return lvLinks;
|
||||
},
|
||||
leLinks()
|
||||
{
|
||||
//TODO (david) abhängig von der LVVerwaltung
|
||||
let base_url = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
||||
|
||||
let leLinks = {};
|
||||
/* this.event.lehreinheit_infos.forEach(lehreinheit => {
|
||||
this.event.lehreinheit_infos.forEach(lehreinheit => {
|
||||
leLinks[lehreinheit.lehreinheit_id] = `${base_url}/LVVerwaltung/stdsem/${lehreinheit.studiensemester_kurzbz}/le/${lehreinheit.lehreinheit_id}`;
|
||||
})*/
|
||||
})
|
||||
return leLinks;
|
||||
},
|
||||
ortString() {
|
||||
return Array.isArray(this.event.ort_kurzbz) ? this.event.ort_kurzbz.join(', ') : this.event.ort_kurzbz;
|
||||
},
|
||||
tags() {
|
||||
if (typeof this.event.tags === 'string') {
|
||||
try {
|
||||
@@ -181,9 +182,27 @@ export default {
|
||||
|
||||
this.modalActions.saveEventTime({kalender_id: this.event.kalender_id, start_time, end_time});
|
||||
},
|
||||
async openTagsModal(tag = null)
|
||||
{
|
||||
await this.$refs.tagsModal.open(this.event, tag);
|
||||
async fetchAssignedTagsByCalender(calendarGroupId) {
|
||||
let result = await this.$api.call(
|
||||
ApiTempusTag.getTagsByCalendar(calendarGroupId),
|
||||
);
|
||||
|
||||
if (result.meta.status === "success")
|
||||
return result.data.filter(tag => !!tag);
|
||||
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("ui", "failed_assigned_tags_fetch_error_message"),
|
||||
);
|
||||
return [];
|
||||
},
|
||||
async onTagsChanged() {
|
||||
let id = this.event.eindeutige_kalender_gruppen_id;
|
||||
if (!id) return;
|
||||
|
||||
this.event.tags = await this.fetchAssignedTagsByCalender(id);
|
||||
},
|
||||
editTag(tag) {
|
||||
this.$refs.tagComponent?.editTag(tag.id);
|
||||
},
|
||||
openRaumvorschlag()
|
||||
{
|
||||
@@ -200,6 +219,26 @@ export default {
|
||||
ort_kurzbz: room,
|
||||
}, 'ort');
|
||||
},
|
||||
renderTags()
|
||||
{
|
||||
let el = this.$refs.tagWrapper;
|
||||
if (!el) return;
|
||||
|
||||
const tagData = this.tags.map(t => ({
|
||||
...t,
|
||||
notiz_id: t.id,
|
||||
bezeichnung: t.beschreibung,
|
||||
}));
|
||||
|
||||
el.replaceChildren(
|
||||
idTagFormatter(
|
||||
this.event.eindeutige_kalender_gruppen_id,
|
||||
tagData,
|
||||
this.$refs.tagComponent,
|
||||
'eindeutige_kalender_gruppen_id'
|
||||
) ?? ''
|
||||
);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.event.type == 'lehreinheit') {
|
||||
@@ -214,6 +253,10 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted()
|
||||
{
|
||||
this.renderTags();
|
||||
},
|
||||
template: /*html*/`
|
||||
<div>
|
||||
<h5>
|
||||
@@ -223,7 +266,7 @@ export default {
|
||||
<tbody>
|
||||
|
||||
<tr v-if="this.event.collisions.length > 0">
|
||||
<th><i class="fa-solid fa-triangle-exclamation text-danger"></i> {{ $p.t('ui','collision') }}</th>
|
||||
<th><i class="fa-solid fa-triangle-exclamation text-danger"></i> {{ $p.t('ui','collision') }}:</th>
|
||||
<td>
|
||||
<div v-for="collision in this.event.collisions" class="d-block">
|
||||
{{collision.message}}
|
||||
@@ -231,13 +274,8 @@ export default {
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('global','datum')?
|
||||
$p.t('global','datum')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>
|
||||
|
||||
<th>{{$p.t('global','datum')+':'}}</th>
|
||||
<td>
|
||||
<form-input
|
||||
ref="editDatumInput"
|
||||
type="DatePicker"
|
||||
@@ -254,11 +292,7 @@ export default {
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('ui','zeitraum')?
|
||||
$p.t('ui','zeitraum')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<th>{{$p.t('ui','zeitraum')+':'}}</th>
|
||||
<td>
|
||||
<template v-if="showRaster">
|
||||
<select v-model="editStundeVon" class="form-select form-select-sm w-auto d-inline-block">
|
||||
@@ -308,7 +342,7 @@ export default {
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{$p.t('global','raum')}}
|
||||
<th>{{$p.t('global','raum')}}:
|
||||
<i
|
||||
class="fa-solid fa-refresh"
|
||||
@click="openRaumvorschlag"
|
||||
@@ -323,7 +357,7 @@ export default {
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>{{$p.t('global','anzahl')}} {{$p.t('global','students')}}
|
||||
<th>{{$p.t('global','anzahl')}} {{$p.t('global','students')}}:
|
||||
</th>
|
||||
<td>
|
||||
{{anzahlSchwund}} ({{anzahl}})
|
||||
@@ -376,40 +410,36 @@ export default {
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="resourcesValue">
|
||||
<th>{{
|
||||
$p.t('ui','betriebsmittel')?
|
||||
$p.t('ui','betriebsmittel')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<th>{{$p.t('ui','betriebsmittel') + ':'}}</th>
|
||||
<td>
|
||||
{{ resourcesValue }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('ui','tags')?
|
||||
$p.t('ui','tags')+':'
|
||||
:''
|
||||
}} <i
|
||||
class="fa-solid fa-tags"
|
||||
@click="openTagsModal(null)"
|
||||
></i>
|
||||
<th>
|
||||
<div class="d-flex align-items-center flex-wrap">
|
||||
{{$p.t('ui','tags')}}:
|
||||
<div class="fw-normal">
|
||||
<core-tag
|
||||
v-if="tagValues.length"
|
||||
ref="tagComponent"
|
||||
:endpoint="tagEndpoint"
|
||||
:values="tagValues"
|
||||
zuordnung_typ="eindeutige_kalender_gruppen_id"
|
||||
show-hover
|
||||
@added="onTagsChanged"
|
||||
@deleted="onTagsChanged"
|
||||
@updated="onTagsChanged"
|
||||
></core-tag>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
<td>
|
||||
<div v-if="tags.length">
|
||||
<span
|
||||
v-for="tag in tags"
|
||||
:key="tag.tag_typ_kurzbz"
|
||||
:class="[tag.style, { tag_done: tag.done }]"
|
||||
@click="openTagsModal(tag)"
|
||||
class="tag disabled"
|
||||
>{{ tag.beschreibung }}</span>
|
||||
</div>
|
||||
<div ref="tagWrapper"></div>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{$p.t('lehre','mail')}} </th>
|
||||
<th>{{$p.t('lehre','mail')}}: </th>
|
||||
<td>
|
||||
<a class="fhc-link-color" :href="'mailto:' + mailto">
|
||||
<i class="fa-solid fa-envelope"></i>
|
||||
@@ -418,7 +448,6 @@ export default {
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<tags-assignment-modal ref="tagsModal"/>
|
||||
<raumauswahl-modal ref="raumModal" @saved="reload()"/>
|
||||
<button type="button" class="btn btn-primary " @click.stop="onSave">{{$p.t('ui', 'speichern')}}</button>
|
||||
</div>`,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { numberPadding, formatDate } from "../../../../helpers/DateHelpers.js"
|
||||
import LvMenu from "../../../Cis/Mylv/LvMenu.js";
|
||||
import TagsAssignmentModal from "../../TagsAssignmentModal.js";
|
||||
import ApiTempusTag from "../../../../api/factory/tempus/tag.js";
|
||||
import CoreTag from '../../../../components/Tag/Tag.js';
|
||||
|
||||
export default {
|
||||
props:{
|
||||
@@ -8,17 +8,20 @@ export default {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
lvMenu:{
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
components:{
|
||||
LvMenu,
|
||||
TagsAssignmentModal
|
||||
components: {
|
||||
CoreTag
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
tagEndpoint: ApiTempusTag
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tagValues() {
|
||||
return this.event.eindeutige_kalender_gruppen_id ? [this.event.eindeutige_kalender_gruppen_id] : [];
|
||||
},
|
||||
lektorenLinks: function () {
|
||||
if (!this.event || !Array.isArray(this.event.lektor) || !this.event.lektor.length) return "a";
|
||||
|
||||
@@ -69,9 +72,27 @@ export default {
|
||||
methodFormatDate: function (d) {
|
||||
return formatDate(d);
|
||||
},
|
||||
async openTagsModal(tag = null)
|
||||
{
|
||||
await this.$refs.tagsModal.open(this.event, tag);
|
||||
async fetchAssignedTagsByCalender(calendarGroupId) {
|
||||
let result = await this.$api.call(
|
||||
ApiTempusTag.getTagsByCalendar(calendarGroupId),
|
||||
);
|
||||
|
||||
if (result.meta.status === "success")
|
||||
return result.data.filter(tag => !!tag);
|
||||
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("ui", "failed_assigned_tags_fetch_error_message"),
|
||||
);
|
||||
return [];
|
||||
},
|
||||
async onTagsChanged() {
|
||||
let id = this.event.eindeutige_kalender_gruppen_id;
|
||||
if (!id) return;
|
||||
|
||||
this.event.tags = await this.fetchAssignedTagsByCalender(id);
|
||||
},
|
||||
editTag(tag) {
|
||||
this.$refs.tagComponent?.editTag(tag.id);
|
||||
},
|
||||
},
|
||||
template: `
|
||||
@@ -129,11 +150,7 @@ export default {
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('ui','teilnehmende')?
|
||||
$p.t('ui','teilnehmende')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<th>{{$p.t('ui','teilnehmende')+':'}}</th>
|
||||
<td>
|
||||
<div v-for="teilnehmer in event.teilnehmer_person" class="d-block">
|
||||
{{teilnehmer.kurzbz}}
|
||||
@@ -144,33 +161,38 @@ export default {
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('ui','tags')?
|
||||
$p.t('ui','tags')+':'
|
||||
:''
|
||||
}} <i
|
||||
class="fa-solid fa-tags"
|
||||
@click="openTagsModal(null)"
|
||||
></i>
|
||||
<th>
|
||||
<div class="d-flex align-items-center flex-wrap">
|
||||
{{$p.t('ui','tags')}}:
|
||||
<div class="fw-normal">
|
||||
<core-tag
|
||||
v-if="tagValues.length"
|
||||
ref="tagComponent"
|
||||
:endpoint="tagEndpoint"
|
||||
:values="tagValues"
|
||||
zuordnung_typ="eindeutige_kalender_gruppen_id"
|
||||
show-hover
|
||||
@added="onTagsChanged"
|
||||
@deleted="onTagsChanged"
|
||||
@updated="onTagsChanged"
|
||||
></core-tag>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
<td>
|
||||
<div v-if="tags.length">
|
||||
<span
|
||||
v-for="tag in tags"
|
||||
:key="tag.tag_typ_kurzbz"
|
||||
:class="[tag.style, { tag_done: tag.done }]"
|
||||
@click="openTagsModal(tag)"
|
||||
class="tag disabled"
|
||||
>{{ tag.beschreibung }}</span>
|
||||
</div>
|
||||
<span
|
||||
v-for="tag in tags"
|
||||
:key="tag.id"
|
||||
:class="[tag.style, { tag_done: tag.done }]"
|
||||
@click="editTag(tag)"
|
||||
class="tag"
|
||||
>{{ tag.beschreibung }}</span>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<tags-assignment-modal ref="tagsModal"/>
|
||||
|
||||
</div>`,
|
||||
}
|
||||
|
||||
@@ -31,21 +31,6 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async open(calendar, tagToEdit = null) {
|
||||
if (!calendar?.eindeutige_kalender_gruppen_id) return;
|
||||
|
||||
this.calendar = calendar;
|
||||
this.availableTags = await this.fetchAvailableTags();
|
||||
this.filteredAvailableTags = [...this.dropdownParsedAvailableTags];
|
||||
this.assignedTags = await this.fetchAssignedTagsByCalender(
|
||||
calendar.eindeutige_kalender_gruppen_id,
|
||||
);
|
||||
|
||||
this.show();
|
||||
|
||||
if (tagToEdit)
|
||||
this.editTag(tagToEdit);
|
||||
},
|
||||
show() {
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
|
||||
@@ -29,7 +29,6 @@ import { useContextMenuActions } from '../../composables/Tempus/ContextMenuActio
|
||||
import MultiWeekPlanModal from './MultiWeekPlanModal.js';
|
||||
import HistoryModal from './HistoryModal.js';
|
||||
import ResourcesAssignmentModal from './ResourcesAssignmentModal.js';
|
||||
import TagsAssignmentModal from './TagsAssignmentModal.js';
|
||||
import { getTempusSearchbarOptions } from './Filters/searchbarOptions.js';
|
||||
import TempusHeader from './Header.js';
|
||||
import TempusAppMenu from './AppMenu.js';
|
||||
@@ -54,7 +53,6 @@ export default {
|
||||
MultiWeekPlanModal,
|
||||
HistoryModal,
|
||||
ResourcesAssignmentModal,
|
||||
TagsAssignmentModal,
|
||||
RaumauswahlModal,
|
||||
RaumauswahlMultiModal,
|
||||
LehreinheitModal,
|
||||
@@ -85,7 +83,6 @@ export default {
|
||||
openRaumauswahl: (orig) => this.$refs.raumModal.show(orig),
|
||||
openLehreinheit: (orig) => this.$refs.lehreinheitModal.show(orig),
|
||||
openResourcesAssignmentModal: (orig) => this.$refs.resourcesAssignmentModal?.open(orig),
|
||||
openTagsModal: (orig) => this.$refs.tagsAssignmentModal?.open(orig),
|
||||
openHistory: (orig) => this.openHistory(orig),
|
||||
deleteEntry: (orig) => this.deleteEntry(orig),
|
||||
syncToLecturer: (orig) => this.syncToLecturer(orig),
|
||||
@@ -1066,7 +1063,6 @@ export default {
|
||||
ref="resourcesAssignmentModal"
|
||||
@save-finished="$refs.calendar.resetEventLoader()"
|
||||
/>
|
||||
<tags-assignment-modal ref="tagsAssignmentModal"/>
|
||||
<history-modal ref="historyModal" :entries="historyEntries" />
|
||||
<reservierung
|
||||
ref="reservierung"
|
||||
|
||||
@@ -18,11 +18,6 @@ export function useContextMenuActions(handlers)
|
||||
icon: 'fa-solid fa-table-list',
|
||||
action: handlers.openResourcesAssignmentModal
|
||||
},
|
||||
{
|
||||
label: 'Tags',
|
||||
icon: 'fa-solid fa-tags',
|
||||
action: handlers.openTagsModal
|
||||
},
|
||||
{
|
||||
label: 'Freischalten für Voransicht',
|
||||
icon: 'fa-solid fa-chalkboard-user',
|
||||
@@ -52,11 +47,6 @@ export function useContextMenuActions(handlers)
|
||||
icon: 'fa-solid fa-door-open',
|
||||
action: handlers.openRaumauswahl
|
||||
},
|
||||
{
|
||||
label: 'Tags',
|
||||
icon: 'fa-solid fa-tags',
|
||||
action: handlers.openTagsModal
|
||||
},
|
||||
{
|
||||
label: 'Delete',
|
||||
icon: 'fa-solid fa-calendar-xmark',
|
||||
|
||||
@@ -5,13 +5,26 @@ if ($result = @$db->db_query("SELECT 1 FROM public.tbl_variablenname WHERE name
|
||||
{
|
||||
if ($db->db_num_rows($result) == 0)
|
||||
{
|
||||
$qry = "INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('roomless_planning', false);
|
||||
INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('priority_room_planning', false);
|
||||
INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('dialog_room_planning', false);";
|
||||
$qry = "INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('roomless_planning', false);";
|
||||
|
||||
if (!$db->db_query($qry))
|
||||
echo '<strong>public.tbl_variablenname '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo 'public.tbl_variablenname: Added "roomless_planning", "priority_room_planning", "dialog_room_planning"<br>';
|
||||
echo 'public.tbl_variablenname: Added "roomless_planning"<br>';
|
||||
}
|
||||
}
|
||||
|
||||
if ($result = @$db->db_query("SELECT 1 FROM public.tbl_variablenname WHERE name = 'room_planning';"))
|
||||
{
|
||||
if ($db->db_num_rows($result) == 0)
|
||||
{
|
||||
$qry = "INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('room_planning', null);
|
||||
DELETE FROM public.tbl_variable WHERE name IN('priority_room_planning', 'dialog_room_planning');
|
||||
DELETE FROM public.tbl_variablenname WHERE name IN('priority_room_planning', 'dialog_room_planning');";
|
||||
|
||||
if (!$db->db_query($qry))
|
||||
echo '<strong>public.tbl_variablenname '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo 'public.tbl_variablenname: Added "room_planning"<br>';
|
||||
}
|
||||
}
|
||||
@@ -37625,6 +37625,46 @@ array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'roomless_prio_planning_error',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Prioritätsraum nicht gefunden und raumlose Planung deaktiviert',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Priority room not found and roomless planning is disabled.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'room_planning',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Raumlplanung',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Room planning',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
|
||||
Reference in New Issue
Block a user