Merge branch 'feature-61730/Cis4_DashboardAnpassungen' into merge_C4_25999_61235_61730

This commit is contained in:
Harald Bamberger
2025-05-22 07:48:23 +02:00
13 changed files with 185 additions and 54 deletions
@@ -107,7 +107,7 @@ class DashboardLib
$emptyoverride = new stdClass();
$emptyoverride->dashboard_id = $dashboard->dashboard_id;
$emptyoverride->uid = $uid;
$emptyoverride->override = '{"' . self::USEROVERRIDE_SECTION . '": {"widgets":{}}}}';
$emptyoverride->override = '{"' . self::USEROVERRIDE_SECTION . '": {"widgets":{}}, "custom": { "widgets" : {}}}';
return $emptyoverride;
}
+29
View File
@@ -16,6 +16,18 @@
color: var(--fhc-link);
}
@media (max-width: 576px){
.widget-icon {
max-height: 250px;
object-fit: cover;
}
.widget-icon-container{
max-width: 250px;
margin-left: auto;
margin-right: auto;
}
}
.empty-tile-hover {
height: 100%;
width: 100%;
@@ -30,6 +42,23 @@
height: 100%;
width: 100%;
background-color:white;
position:relative;
}
.dashboard-section > .newGridRow{
position:absolute;
width:20px;
height:20px;
padding:0;
bottom:0;
left:50%;
transform:translate(-50%, 50%);
background-color:white;
}
.newGridRow:hover {
color:white;
background-color:#6c757d;
}
.empty-tile-hover:hover {
+1
View File
@@ -300,6 +300,7 @@ app.use(primevue.config.default, {
tooltip: 8000
}
})
app.directive('tooltip', primevue.tooltip);
app.use(PluginsPhrasen);
app.use(Theme);
app.directive('contrast', contrast);
+7 -1
View File
@@ -177,7 +177,13 @@ export default {
});
remove.forEach(wid => this.widgetRemove(name, wid));
}
this.sections = this.sections.sort((section1, section2) => section2.widgets.length - section1.widgets.length);
this.sections = this.sections.sort((section1, section2) => {
if(section1.name == 'custom')
return 1;
if (section2.name == 'custom')
return -1;
return section2.widgets.length - section1.widgets.length;
});
}).catch(err => console.error('ERROR:', err));
},
async beforeMount() {
+6 -1
View File
@@ -41,6 +41,9 @@ export default {
"item_data",
"place",
"setup",
"dragstate",
"resizeOverlay",
"additionalRow"
],
computed: {
maxHeight(){
@@ -153,7 +156,8 @@ export default {
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
</div>
<div v-else-if="!hidden || editMode" :id="widgetID" class="dashboard-item card overflow-hidden h-100 position-relative" :class="arguments && arguments.className ? arguments.className : ''">
<div v-else-if="!hidden || editMode" :id="widgetID" class="dashboard-item card overflow-hidden h-100 position-relative" :class="{'draggedItem':dragstate, 'dashboard-item-overlay':resizeOverlay, [arguments?.className]:arguments && arguments.className}">
<div v-show="!dragstate" class="h-100 card border-0">
<div v-if="widget" class="card-header d-flex ps-0 pe-2 align-items-center">
<Transition>
<span v-if="editMode && !isPinned" drag-action="move" class="col-auto mx-2 px-2 cursor-move"><i class="fa-solid fa-grip-vertical"></i></span>
@@ -221,5 +225,6 @@ export default {
</template>
</div>
</height-transition>
</div>
</div>`,
};
+11 -9
View File
@@ -1,5 +1,4 @@
import BsConfirm from "../Bootstrap/Confirm.js";
import SectionModal from "../Bootstrap/Alert.js";
import DropGrid from '../Drop/Grid.js'
import DashboardItem from "./Item.js";
import CachedWidgetLoader from "../../composables/Dashboard/CachedWidgetLoader.js";
@@ -41,6 +40,7 @@ export default {
gridWidth: 1,
gridHeight: null,
draggedItem:null,
additionalRow:false,
}
},
provide() {
@@ -108,13 +108,13 @@ export default {
},
showSectionInformation(){
if (this.name == "general"){
SectionModal.popup(this.$p.t('dashboard', 'dashboardGeneralSectionDescription'));
return this.$p.t('dashboard', 'dashboardGeneralSectionDescription');
}
else if(this.name == "custom"){
SectionModal.popup(this.$p.t('dashboard', 'dashboardCustomSectionDescription'));
return this.$p.t('dashboard', 'dashboardCustomSectionDescription');
}
else{
SectionModal.popup(this.$p.t('dashboard', 'dashboardSectionDescription', [this.name]));
return this.$p.t('dashboard', 'dashboardSectionDescription', [this.name]);
}
},
handleConfigOpened() {
@@ -209,18 +209,20 @@ export default {
});
},
template: `
<h4 v-if="editModeIsActive" class=" mb-0">
<i @click="showSectionInformation(name)" class="fa-solid fa-circle-info section-info" ></i>
<h4 v-if="editModeIsActive" class=" mb-2">
<i v-tooltip="showSectionInformation(name)" class="fa-solid fa-circle-info section-info" ></i>
{{sectionNameTranslation()}}:
</h4>
<div class="dashboard-section position-relative pb-3 border-bottom" ref="container" :style="getSectionStyle">
<drop-grid v-model:cols="gridWidth" :items="items" :itemsSetup="computedWidgetsSetup" :active="editModeIsActive" :resize-limit="checkResizeLimit" :margin-for-extra-row=".01" @draggedItem="draggedItem=$event" @rearrange-items="updatePositions" @gridHeight="gridHeight=$event" >
<button v-tooltip="$p.t('dashboard','addLine')" v-if="!additionalRow && editModeIsActive" @click="additionalRow=true" class="btn btn-outline-secondary rounded-circle newGridRow d-flex justify-content-center align-items-center">+</button>
<drop-grid v-model:cols="gridWidth" v-model:additionalRow="additionalRow" :items="items" :itemsSetup="computedWidgetsSetup" :active="editModeIsActive" :resize-limit="checkResizeLimit" :margin-for-extra-row=".01" @draggedItem="draggedItem=$event" @rearrange-items="updatePositions" @gridHeight="gridHeight=$event" >
<template #default="item">
<div v-if="item.placeholder" class="empty-tile-hover" @click="$emit('widgetAdd', name, { widget: 1, config: {}, place: {[gridWidth]: {x:item.x,y:item.y,w:1,h:1}}, custom: 1 })"></div>
<div v-else-if="item.blank || (item.widgetid && item.widgetid == draggedItem?.data.widgetid)" :class="{'dashboard-item-overlay':item.resizeOverlay}" class="dashboard-item card overflow-hidden h-100 position-relative draggedItem" ></div>
<div v-if="item.placeholder" class="empty-tile-hover" @pointerdown="$emit('widgetAdd', name, { widget: 1, config: {}, place: {[gridWidth]: {x:item.x,y:item.y,w:1,h:1}}, custom: 1 })"></div>
<dashboard-item
v-else
:id="item.widget"
:dragstate="item.blank || (item.widgetid && item.widgetid == draggedItem?.data.widgetid)"
:resizeOverlay="item.resizeOverlay"
:widgetID="item.id"
:width="item.w"
:height="item.h"
@@ -36,11 +36,11 @@ export default {
<bs-modal ref="modal" class="fade" :dialog-class="{'modal-fullscreen-sm-down': 1, 'modal-xl': widgets && widgets.length > 0}" @hiddenBsModal="close">
<template v-slot:title>Create new widget</template>
<template v-slot:default>
<div v-if="widgets" class="row">
<div v-if="widgets" class="row g-2">
<div v-if="!widgets.length">
No Widgets available
</div>
<div v-for="widget in widgets" :key="widget.widget_id" class="col-sm-6 col-md-4 col-lg-3 col-xl-2">
<div v-for="widget in widgets" :key="widget.widget_id" class="widget-icon-container col-sm-6 col-md-4 col-lg-3 col-xl-2">
<widget-icon @select="pick" :widget="widget" ></widget-icon>
</div>
</div>
@@ -20,7 +20,7 @@ export default {
emits:["select"],
template: /*html */`
<div class="card h-100" @click="$emit('select',widget.widget_id);">
<img class="card-img-top" :src="path(widget.setup.icon)" :alt="'pictogram for ' + (widget.setup.name || widget.widget_kurzbz)">
<img class="card-img-top widget-icon" :src="path(widget.setup.icon)" :alt="'pictogram for ' + (widget.setup.name || widget.widget_kurzbz)">
<div class="card-body">
<h5 class="card-title">{{ widget.setup.name || widget.widget_kurzbz }}</h5>
<p class="card-text">{{ widget.beschreibung }}</p>
+40 -32
View File
@@ -26,6 +26,10 @@ export default {
type: Number,
default: 0
},
additionalRow:{
type: Boolean,
default: false,
}
},
emits: [
"rearrangeItems",
@@ -48,7 +52,6 @@ export default {
draggedOffset: [0,0],
draggedItem: null,
draggedNode: null,
additionalRow: null,
reorderedItems:[],
clonedWidget:null,
}
@@ -60,6 +63,14 @@ export default {
},
},
computed: {
additionalRowComputed: {
get() {
return this.additionalRow;
},
set(value) {
this.$emit('update:additionalRow', value);
}
},
items_hashmap() {
let items = {};
this.items.forEach(item => {
@@ -117,10 +128,19 @@ export default {
return [...this.placedItems, ...this.items_placeholders];
},
rows() {
if ((this.mode == MODE_MOVE || this.mode == MODE_RESIZE) && this.dragGrid){
return this.dragGrid.h;
if (this.additionalRowComputed) {
return this.grid ? (this.grid.h+1) : 1;
}
return this.grid ? this.grid.h : 1;
/* if ((this.mode == MODE_MOVE || this.mode == MODE_RESIZE) && this.dragGrid){
return this.dragGrid.h;
}
if (this.mode == MODE_IDLE) {
if (this.additionalRowComputed) {
return this.grid ? (this.grid.h+1) : 1;
}
}
return this.grid ? this.grid.h : 1; */
},
gridStyle() {
const addH = this.active ? this.marginForExtraRow : 0;
@@ -347,17 +367,12 @@ export default {
});
},
mouseLeave() {
if (this.mode == MODE_IDLE) {
/* if (this.mode == MODE_IDLE) {
this.x = -1;
this.y = -1;
if (this.additionalRow !== null) {
let gridHeight = this.grid.getMaxY() + 1;
if(this.grid.h>gridHeight){
this.grid.h = gridHeight;
}
this.additionalRow = null;
}
}
this.additionalRowComputed = false;
} */
},
updateCursor(evt) {
if (!this.active) {
@@ -380,18 +395,6 @@ export default {
if (this.x == gridX && this.y == gridY)
return false;
if (this.mode == MODE_IDLE) {
if (this.additionalRow === null && this.y == this.rows-1 && gridY == this.rows) {
this.additionalRow = this.grid.h;
this.grid.h += 1;
} else if (this.additionalRow !== null && gridY != this.rows - 1) {
let gridHeight = this.grid.getMaxY() + 1;
if(this.grid.h > gridHeight){
this.grid.h = gridHeight;
}
this.additionalRow = null;
}
}
this.x = gridX;
this.y = gridY;
@@ -405,6 +408,7 @@ export default {
}
},
startMove(evt, item) {
if (!this.active)
return;
@@ -413,14 +417,15 @@ export default {
this.grid.h += 1;
this.draggedItem = item;
this.$emit('draggedItem',item);
this.draggedNode = evt.target;
this.draggedNode = evt.target.closest(".drop-grid-item");
//clones the widget for the drag Image
let clone = evt.target.cloneNode(true);
let clone = evt.target.closest(".drop-grid-item")?.cloneNode(true);
clone.style.zIndex = 5;
clone.classList.add("widgetClone");
this.$refs.container.appendChild(clone);
this.clonedWidget = clone;
this.draggedOffset = [item.x - this.x, item.y - this.y];
this._dragStart(evt, item);
},
@@ -480,6 +485,7 @@ export default {
}
},
dragCancel() {
this.additionalRowComputed = false;
this.toggleDraggedItemOverlay(false);
this.mode = MODE_IDLE;
this.positionUpdates = null;
@@ -498,9 +504,10 @@ export default {
Array.from(document.getElementsByClassName("denied-dragging-animation"))?.forEach(ele => {
ele.classList.remove("denied-dragging-animation");
})
let widgetClones = document.getElementsByClassName("widgetClone");
for(let widget of widgetClones){
this.$refs.container.removeChild(widget);
for (let i=0; i <widgetClones.length; i++){
this.$refs.container.removeChild(widgetClones[i]);
}
if (!this.active || this.x < 0 || this.y < 0 || this.x >= this.cols)
@@ -528,6 +535,7 @@ export default {
return updated;
},
emptyTileClicked() {
this.additionalRowComputed = false;
this.$emit('newItem', this.x, this.y);
},
updateCursorOnMouseMove(evt){
@@ -614,7 +622,7 @@ export default {
<TransitionGroup tag="div">
<grid-item
ref="gridItems"
v-for="(item,index) in ((mode != 1 || mode != 2) && active ? placedItems_withPlaceholders : placedItems)"
v-for="(item,index) in ((mode != 1 && mode != 2) && active ? placedItems_withPlaceholders : placedItems)"
:key="item.data.id"
:item="item"
@start-move="startMove"
@@ -623,8 +631,8 @@ export default {
@start-resize="startResize"
@dragging="dragging"
@end-drag="dragCancel"
@drop-drag="dragEnd"
@touchEvent="updateCursorOnMouseMove"
@touch-end="dragEnd();mouseUp();"
@touch-start="updateCursorOnMouseMove($event); mouseDown();"
class="position-absolute"
:active="active"
:style="{
+8 -7
View File
@@ -17,7 +17,8 @@ export default {
"endDrag",
"dropDrag",
"item",
"touchEvent"
"touchStart",
"touchEnd",
],
data() {
return {
@@ -54,16 +55,16 @@ export default {
},
touchDragEnd(evt) {
if (!this.dragging)
//return evt.preventDefault();
return;
return;
this.dragging = false;
this.$emit('dropDrag', evt);
this.$emit('touchEnd', evt);
},
touchStart(event){
this.$emit('touchEvent', event);
this.$emit('touchStart', event);
this.registerDragAction(event);
this.tryDragStart(event, this.item);
}
},
},
template: `
<div class="drop-grid-item"
@@ -73,7 +74,7 @@ export default {
@touchend="touchDragEnd"
@dragstart="tryDragStart($event, item)"
@drag="$emit('dragging',$event)"
@touchmove="$emit('dragging',$event)"
@touchmove.prevent="$emit('dragging',$event)"
@dragend="$emit('endDrag', $event)"
:draggable="active && !item.placeholder && dragAction != ''">
<slot v-bind="item"></slot>
+2
View File
@@ -74,6 +74,8 @@ require_once('dbupdate_3.4/55968_index_anrechnung.php');
require_once('dbupdate_3.4/25999_locale_update.php');
require_once('dbupdate_3.4/55289_pep_fine_tuning.php');
require_once('dbupdate_3.4/55614_perm_verwaltetoe.php');
require_once('dbupdate_3.4/61730_Dashboard_Anpassungen.php');
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
echo '<H2>Pruefe Tabellen und Attribute!</H2>';
@@ -0,0 +1,57 @@
<?php
$result = @$db->db_query("SELECT preset_id FROM dashboard.tbl_dashboard_preset WHERE preset ? 'widgets'");
$result_num_rows = $db->db_num_rows($result);
$errorList = array();
for($i = 0; $i < $result_num_rows; $i++)
{
$row = $db->db_fetch_object($result, $i);
$qry = "
UPDATE dashboard.tbl_dashboard_preset
SET preset =
COALESCE(
(SELECT jsonb_object_agg(keys,values) FROM (
SELECT key AS keys,jsonb_build_object('widgets',to_jsonb(value)) AS values
FROM jsonb_each(preset->'widgets')
) AS subquery
),preset)
WHERE preset_id = ".$row->preset_id;
$db->db_query($qry);
if (!$db->db_query($qry))
array_push($errorList,'<br><strong>dashboard.tbl_dashboard_preset: ' . $db->db_last_error() . '</strong><br>') ;
}
$result = @$db->db_query("SELECT override_id FROM dashboard.tbl_dashboard_benutzer_override WHERE override ? 'widgets'");
$result_num_rows = $db->db_num_rows($result);
for($i = 0; $i < $result_num_rows; $i++)
{
$row = $db->db_fetch_object($result, $i);
$qry = "
UPDATE dashboard.tbl_dashboard_benutzer_override
SET override =
COALESCE(
(SELECT jsonb_object_agg(keys,values) FROM (
SELECT key AS keys,jsonb_build_object('widgets',to_jsonb(value)) AS values
FROM jsonb_each(override->'widgets')
) AS subquery
),override)
WHERE override_id = ".$row->override_id;
$db->db_query($qry);
if (!$db->db_query($qry))
array_push($errorList,'<br><strong>dashboard.tbl_dashboard_benutzer_override: ' . $db->db_last_error() . '</strong><br>') ;
}
if(empty($errorList)){
echo '<br>successfully updated dashboard.tbl_dashboard_preset and dashboard.tbl_dashboard_benutzer_override';
}
else{
foreach($errorList as $error){
echo $error;
}
}
+20
View File
@@ -40581,6 +40581,26 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'dashboard',
'phrase' => 'addLine',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Weitere Zeile hinzufügen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Add another line',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dashboard',