From d7c2362a0e7d4f2fd6784f6e849812cc179e6eb4 Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Tue, 22 Nov 2022 14:39:33 +0100 Subject: [PATCH 1/5] double widgets bug --- application/models/dashboard/Widget_model.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/models/dashboard/Widget_model.php b/application/models/dashboard/Widget_model.php index 4e5a31502..554c7dea6 100644 --- a/application/models/dashboard/Widget_model.php +++ b/application/models/dashboard/Widget_model.php @@ -15,8 +15,8 @@ class Widget_model extends DB_Model public function getWithAllowedForDashboard($dashboard_id) { $this->addSelect($this->dbTable . '.*'); - $this->addSelect('CASE WHEN dashboard_id = ? THEN 1 ELSE 0 END AS allowed', false); - $this->addJoin('dashboard.tbl_dashboard_widget', 'widget_id', 'LEFT'); + $this->addSelect('CASE WHEN dashboard_id IS NULL THEN 0 ELSE 1 END AS allowed', false); + $this->db->join('dashboard.tbl_dashboard_widget dw', $this->dbTable . '.widget_id=dw.widget_id AND dashboard_id = ?', 'LEFT', false); return $this->execQuery($this->db->get_compiled_select($this->dbTable), [$dashboard_id]); } From d51a95a8a09dcadbbd11393135206f4513696ca6 Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Thu, 24 Nov 2022 11:48:46 +0100 Subject: [PATCH 2/5] test controller & views --- application/controllers/Test.php | 63 ++++++++++++++++++++++++++++++++ application/views/test/Admin.php | 32 ++++++++++++++++ application/views/test/Test.php | 32 ++++++++++++++++ public/js/apps/Test.js | 19 ++++++++++ 4 files changed, 146 insertions(+) create mode 100644 application/controllers/Test.php create mode 100644 application/views/test/Admin.php create mode 100644 application/views/test/Test.php create mode 100644 public/js/apps/Test.js diff --git a/application/controllers/Test.php b/application/controllers/Test.php new file mode 100644 index 000000000..497f12f85 --- /dev/null +++ b/application/controllers/Test.php @@ -0,0 +1,63 @@ + 'dashboard/benutzer:r', + 'db' => 'dashboard/benutzer:r', + 'admin' => 'dashboard/admin:r', + ) + ); + + $this->load->library('AuthLib'); + + $this->_setAuthUID(); // sets property uid + + $this->setControllerId(); // sets the controller id + } + + // ----------------------------------------------------------------------------------------------------------------- + // Public methods + public function index() + { + $this->load->view('test/Test.php', ['dashboard' => 'CIS']); + } + + // Public methods + public function db($dashboard) + { + $this->load->view('test/Test.php', ['dashboard' => $dashboard]); + } + + public function admin() + { + $this->load->view('test/Admin.php', []); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Private methods + + /** + * Retrieve the UID of the logged user and checks if it is valid + */ + private function _setAuthUID() + { + $this->_uid = getAuthUID(); + + if (!$this->_uid) show_error('User authentification failed'); + } + +} diff --git a/application/views/test/Admin.php b/application/views/test/Admin.php new file mode 100644 index 000000000..837f6411b --- /dev/null +++ b/application/views/test/Admin.php @@ -0,0 +1,32 @@ +load->view('templates/FHC-Header', + array( + 'title' => 'FH-Complete', + 'bootstrap5' => true, + 'fontawesome6' => true, + 'axios027' => true, + 'restclient' => true, + 'vue3' => true, + 'customJSModules' => ['public/js/apps/Test.js'], + 'customCSSs' => [ + 'public/css/components/dashboard.css' + ], + 'navigationcomponent' => true + ) +); +?> + +
+ + +
+
+

Dashboard

+
+ + + +
+
+ +load->view('templates/FHC-Footer'); ?> diff --git a/application/views/test/Test.php b/application/views/test/Test.php new file mode 100644 index 000000000..d297bf4ec --- /dev/null +++ b/application/views/test/Test.php @@ -0,0 +1,32 @@ +load->view('templates/FHC-Header', + array( + 'title' => 'FH-Complete', + 'bootstrap5' => true, + 'fontawesome6' => true, + 'axios027' => true, + 'restclient' => true, + 'vue3' => true, + 'customJSModules' => ['public/js/apps/Test.js'], + 'customCSSs' => [ + 'public/css/components/dashboard.css' + ], + 'navigationcomponent' => true + ) +); +?> + +
+ + +
+
+

Dashboard

+
+ + + +
+
+ +load->view('templates/FHC-Footer'); ?> diff --git a/public/js/apps/Test.js b/public/js/apps/Test.js new file mode 100644 index 000000000..cdf3e78f3 --- /dev/null +++ b/public/js/apps/Test.js @@ -0,0 +1,19 @@ +import {CoreNavigationCmpt} from '../components/navigation/Navigation.js'; +import CoreDashboard from '../components/Dashboard/Dashboard.js'; +import DashboardAdmin from '../components/Dashboard/Admin.js'; + +Vue.createApp({ + data: () => ({ + appSideMenuEntries: {} + }), + components: { + CoreNavigationCmpt, + DashboardAdmin, + CoreDashboard/*, + "CoreFilterCmpt": CoreFilterCmpt, + "verticalsplit": verticalsplit, + "searchbar": searchbar*/ + }, + mounted() { + } +}).mount('#main'); From 3e178928315a0afab2bcae909dec6ee467d284db Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Thu, 24 Nov 2022 11:50:09 +0100 Subject: [PATCH 3/5] fixed path to news placeholder image --- public/js/components/DashboardWidget/News.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/public/js/components/DashboardWidget/News.js b/public/js/components/DashboardWidget/News.js index 6b5fc73d1..830af955e 100644 --- a/public/js/components/DashboardWidget/News.js +++ b/public/js/components/DashboardWidget/News.js @@ -22,7 +22,10 @@ export default { } return this.allNewsList.slice(0, quantity); - } + }, + placeHolderImgURL: function() { + return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'skin/images/fh_technikum_wien_illustration_klein.png'; + } }, created(){ axios @@ -69,7 +72,7 @@ export default {
- +
{{ news.betreff }}
@@ -85,7 +88,7 @@ export default { ` -} \ No newline at end of file +} From 3e0aa849d4dcd71832847920026a12a58043fca9 Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Thu, 24 Nov 2022 11:52:01 +0100 Subject: [PATCH 4/5] bugfixes & "+" background --- application/controllers/dashboard/Config.php | 8 ++- .../js/components/Dashboard/Admin/Presets.js | 13 +++- public/js/components/Dashboard/Section.js | 71 ++++++++++++++----- 3 files changed, 73 insertions(+), 19 deletions(-) diff --git a/application/controllers/dashboard/Config.php b/application/controllers/dashboard/Config.php index 213781b74..b9c4c6c31 100644 --- a/application/controllers/dashboard/Config.php +++ b/application/controllers/dashboard/Config.php @@ -207,7 +207,13 @@ class Config extends Auth_Controller foreach ($funktionen as $funktion) { $conf = $this->DashboardLib->getPreset($db, $funktion); if ($conf) - $result[$funktion] = json_decode($conf->preset, true)['widgets'][$funktion]; + { + $preset = json_decode($conf->preset, true); + if (!isset($preset['widgets']) || !isset($preset['widgets'][$funktion])) + $result[$funktion] = []; + else + $result[$funktion] = $preset['widgets'][$funktion]; + } else $result[$funktion] = []; } diff --git a/public/js/components/Dashboard/Admin/Presets.js b/public/js/components/Dashboard/Admin/Presets.js index 44ff2f854..a86de1966 100644 --- a/public/js/components/Dashboard/Admin/Presets.js +++ b/public/js/components/Dashboard/Admin/Presets.js @@ -14,6 +14,7 @@ export default { data: () => ({ funktionen: {}, sections: [], + tmpLoading: '' }), computed: { apiurl() { @@ -117,10 +118,14 @@ export default { loadSections(evt) { let funktionen = Array.from(evt.target.querySelectorAll("option:checked"),e=>e.value); this.sections = []; + this.tmpLoading = funktionen.join('###'); axios.get(this.apiurl + '/Config/PresetBatch', {params: { db: this.dashboard, funktionen }}).then(res => { + if (this.tmpLoading !== funktionen.join('###')) + return; // NOTE(chris): prevent race condition + for (var section in res.data.retval) { let widgets = []; for (var wid in res.data.retval[section]) { @@ -145,10 +150,16 @@ export default { }); }).catch(err => console.error('ERROR:', err)); }, + watch: { + dashboard() { + // TODO(chris): this should be done without a watcher + this.loadSections({target:this.$refs.funktionenList}); + } + }, template: `
-
diff --git a/public/js/components/Dashboard/Section.js b/public/js/components/Dashboard/Section.js index 250a26a7b..84bcdd58e 100644 --- a/public/js/components/Dashboard/Section.js +++ b/public/js/components/Dashboard/Section.js @@ -24,13 +24,16 @@ export default { data() { return { gridWidth: 0, - containerRect: {top:0,left:0}, changeHeight: 1, movedObjects: [], editMode: this.adminMode ? 1 : 0, - gridXLast: 0, - gridYLast: 0, - dataTransfer: {} + gridXLast: -1, // NOTE(chris): 0 based + gridYLast: -1, + dragging: 0, + dataTransfer: {}, + gridAddFound: false, + gridXAdd: -1, // NOTE(chris): 0 based + gridYAdd: -1 } }, computed: { @@ -38,7 +41,7 @@ export default { this.widgets.forEach((item,i) => item.index = i); return this.widgets; }, - itemCoords() { + itemCoords() { // NOTE(chris): 1 based if (!this.gridWidth) return []; let itemCoords = this.items.map(item => item.place[this.gridWidth] || this.createItemPlacement(item)); @@ -103,11 +106,13 @@ export default { if (!this.gridWidth || !this.changeHeight) return 0; let minH = 0; - this.itemCoords.forEach((item,i) => minH = Math.max(minH, (!this.editMode && this.items[i].hidden) ? 0 : item.y + item.h - 1)); + this.itemCoords.forEach((item,i) => minH = Math.max(minH, (!this.editMode && this.items[i].hidden) ? 0 : item.y - 1 + item.h)); // TODO(chris): the extraline should only be present if all slots are occupied - return minH + this.editMode; + if (minH == 0 && this.editMode) + return 1; + return minH + this.editMode*this.dragging; }, - gridOccupiers() { + gridOccupiers() { // NOTE(chris): 0 based let occupiers = []; let gridWidth = this.gridWidth; this.items.forEach(item => { @@ -123,20 +128,26 @@ export default { } }); return occupiers; + }, + cssBg() { + if (!this.editMode || this.dragging || !this.gridAddFound) + return 'transparent'; + let x = this.gridXAdd, y = this.gridYAdd, h = this.gridHeight-1 || 1, w = this.gridWidth-1 || 1; + return `url('data:image/svg+xml;utf8,')` + (100 * x/w) + '% ' + (100 * y/h) + '%/' + (100/this.gridWidth) + '% ' + (100/this.gridHeight) + '% no-repeat;cursor:pointer'; } }, methods: { addWidget(evt) { if (evt.target != this.$refs.container || !this.editMode) return; - const rect = this.containerRect; + const rect = this.$refs.container.getBoundingClientRect(); const gridX = Math.floor(this.gridWidth * (evt.clientX - rect.left) / this.$refs.container.clientWidth); const gridY = Math.floor(this.gridHeight * (evt.clientY - rect.top) / this.$refs.container.clientHeight); if (this.gridOccupiers[gridY * this.gridWidth + gridX] === undefined) { let widget = { widget: 1, config: {}, place: {}, custom: 1 }; widget.place[this.gridWidth] = { - x: gridX, - y: gridY, + x: gridX+1, + y: gridY+1, w: 1, h: 1 }; @@ -162,7 +173,29 @@ export default { });*/ return item.place[this.gridWidth]; }, + onMouseMove(evt) { + if (!this.editMode || this.dragging) { + this.gridXAdd = this.gridYAdd = -1; + return; + } + + const rect = this.$refs.container.getBoundingClientRect(); + const gridX = Math.floor(this.gridWidth * (evt.clientX - rect.left) / this.$refs.container.clientWidth); + const gridY = Math.floor(this.gridHeight * (evt.clientY - rect.top) / this.$refs.container.clientHeight); + + if (this.gridXAdd == gridX && this.gridYAdd == gridY) + return; + // TODO(chris): only mark it when its not occupied + this.gridXAdd = gridX; + this.gridYAdd = gridY; + this.gridAddFound = (this.gridOccupiers[gridX + gridY * this.gridWidth] === undefined); + }, + onMouseLeave() { + this.gridXAdd = this.gridYAdd = -1; + this.gridAddFound = false; + }, startDrag(evt, item) { + this.dragging = 1; this.gridXLast = -1; this.gridYLast = -1; item._x = this.itemCoords[item.index].x; @@ -178,6 +211,7 @@ export default { } }, startResize(evt, item) { + this.dragging = 1; this.gridXLast = -1; this.gridYLast = -1; item._w = this.itemCoords[item.index].w; @@ -239,7 +273,7 @@ export default { onDragOver(evt) { let id, x, y, w, h; const action = this.dataTransfer.action; - const rect = this.containerRect; + const rect = this.$refs.container.getBoundingClientRect(); const gridX = Math.floor(this.gridWidth * (evt.clientX - rect.left) / this.$refs.container.clientWidth); const gridY = Math.floor(this.gridHeight * (evt.clientY - rect.top) / this.$refs.container.clientHeight); @@ -304,6 +338,9 @@ export default { } }, onDrop() { + this.dragging = 0; + this.gridXLast = -1; + this.gridYLast = -1; let id = 0; let update = {}; while ((id = this.movedObjects.pop())) { @@ -376,14 +413,12 @@ export default { let self = this; let cont = self.$refs.container; self.gridWidth = window.getComputedStyle(cont).getPropertyValue('grid-template-columns').split(" ").length; - self.containerRect = cont.getBoundingClientRect(); window.addEventListener('resize', () => { for (const child of cont.children) { child.style.display = 'none'; } self.gridWidth = window.getComputedStyle(cont).getPropertyValue('grid-template-columns').split(" ").length; - self.containerRect = cont.getBoundingClientRect(); for (const child of cont.children) { child.style.display = ''; } @@ -394,14 +429,16 @@ export default { {{name}} -
+
+ @dragenter.prevent + @mousemove="onMouseMove" + @mouseleave="onMouseLeave"> Date: Thu, 24 Nov 2022 11:52:09 +0100 Subject: [PATCH 5/5] access rights --- application/controllers/dashboard/Widget.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/controllers/dashboard/Widget.php b/application/controllers/dashboard/Widget.php index 9a878fa36..07c57ea73 100644 --- a/application/controllers/dashboard/Widget.php +++ b/application/controllers/dashboard/Widget.php @@ -11,9 +11,9 @@ class Widget extends Auth_Controller { parent::__construct( array( - 'index' => 'dashboard/benutzer:r', + 'index' => ['dashboard/benutzer:r', 'dashboard/admin:r'], 'getAll' => 'dashboard/admin:r', - 'getWidgetsForDashboard' => 'dashboard/benutzer:rw', + 'getWidgetsForDashboard' => ['dashboard/benutzer:rw', 'dashboard/admin:r'], 'setAllowed' => 'dashboard/admin:rw' ) );