diff --git a/application/controllers/api/frontend/v1/dashboard/DashboardAdmin.php b/application/controllers/api/frontend/v1/dashboard/DashboardAdmin.php
index eb9d02776..31e73b6ba 100644
--- a/application/controllers/api/frontend/v1/dashboard/DashboardAdmin.php
+++ b/application/controllers/api/frontend/v1/dashboard/DashboardAdmin.php
@@ -32,11 +32,6 @@ class DashboardAdmin extends FHCAPI_Controller
'createDashboard' => 'dashboard/admin:rw',
'updateDashboard' => 'dashboard/admin:rw',
'deleteDashboard' => 'dashboard/admin:rw',
- 'loadWidget' => ['dashboard/benutzer:r', 'dashboard/admin:r'],
- 'getAllWidgets' => 'dashboard/admin:r',
- 'getWidgetsForDashboard' => ['dashboard/benutzer:rw', 'dashboard/admin:r'],
- 'setWidgetAllowed' => 'dashboard/admin:rw',
-
'index' => 'dashboard/benutzer:r',
'dummy' => 'dashboard/benutzer:r',
'genWidgetId' => 'dashboard/benutzer:rw',
@@ -156,52 +151,6 @@ class DashboardAdmin extends FHCAPI_Controller
$this->terminateWithSuccess($result);
}
- public function getAllWidgets()
- {
- $dashboard_id = $this->input->get('dashboard_id');
- if(!$dashboard_id)
- {
- return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Dashboard ID']), self::ERROR_TYPE_GENERAL);
- }
- //$this->terminateWithError($dashboard_id);
- $result = $this->WidgetModel->getWithAllowedForDashboard($dashboard_id);
-
- if (isError($result))
- $this->terminateWithError($result, self::ERROR_TYPE_GENERAL);
-
- $this->terminateWithSuccess(getData($result) ?: []);
- }
-
- public function setWidgetAllowed()
- {
- $dashboard_id = $this->input->post('dashboard_id');
- $widget_id = $this->input->post('widget_id');
- $action = $this->input->post('action');
-
- if ($action == 'add')
- {
- $result = $this->DashboardWidgetModel->insert([
- 'dashboard_id' => $dashboard_id,
- 'widget_id' => $widget_id
- ]);
- }
- elseif ($action == 'delete')
- {
- $result = $this->DashboardWidgetModel->delete([
- 'dashboard_id' => $dashboard_id,
- 'widget_id' => $widget_id
- ]);
- }
- else
- {
- $this->terminateWithError("action value invalid", self::ERROR_TYPE_GENERAL);
- }
- if (isError($result))
- $this->terminateWithError($result, self::ERROR_TYPE_GENERAL);
-
- $this->terminateWithSuccess(getData($result) ?: []);
- }
-
//Presets
public function funktionen()
{
diff --git a/application/controllers/api/frontend/v1/dashboard/Widget.php b/application/controllers/api/frontend/v1/dashboard/Widget.php
new file mode 100644
index 000000000..cd01d9102
--- /dev/null
+++ b/application/controllers/api/frontend/v1/dashboard/Widget.php
@@ -0,0 +1,137 @@
+.
+ */
+
+if (! defined('BASEPATH')) exit('No direct script access allowed');
+
+/**
+ * This controller operates between (interface) the JS (GUI) and the back-end
+ * Provides data to the ajax get calls about the users dashboard
+ * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
+ */
+class Widget extends FHCAPI_Controller
+{
+ public function __construct()
+ {
+ parent::__construct([
+ 'get' => ['dashboard/benutzer:r', 'dashboard/admin:r'],
+ 'list' => 'dashboard/admin:r',
+ 'listAllowed' => ['dashboard/benutzer:rw', 'dashboard/admin:r'],
+ 'setAllowed' => 'dashboard/admin:rw'
+ ]);
+
+ // Libraries
+ $this->load->library('dashboard/DashboardLib');
+
+ // Models
+ $this->load->model('dashboard/Widget_model', 'WidgetModel');
+ }
+
+ public function get($id)
+ {
+ $result = $this->WidgetModel->load($id);
+
+ $widget = $this->getDataOrTerminateWithError($result);
+
+ if (!$widget)
+ return $this->terminateWithSuccess([
+ "widget_id" => 0,
+ "widget_kurzbz" => "notfound",
+ "arguments" => [
+ "className" => 'alert-danger',
+ "title" => 'Widget Not Found',
+ "msg" => 'The widget with the id ' . $id . ' could not be found'
+ ],
+ "setup" => [
+ "name" => 'Widget Not Found',
+ "file" => absoluteJsImportUrl('public/js/components/DashboardWidget/Default.js'),
+ "width" => 1,
+ "height" => 1
+ ]
+ ]);
+
+ $widget = current($widget);
+ $widget->arguments = json_decode($widget->arguments);
+ $tmpsetup = json_decode($widget->setup);
+ $tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
+ $widget->setup = $tmpsetup;
+
+ $this->terminateWithSuccess($widget);
+ }
+
+ public function list($dashboard)
+ {
+ $result = $this->WidgetModel->getWithAllowedForDashboard($dashboard);
+
+ $widgets = $this->getDataOrTerminateWithError($result);
+
+ $widgets = array_map(function ($widget) {
+ $widget->arguments = json_decode($widget->arguments);
+ $tmpsetup = json_decode($widget->setup);
+ $tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
+ $widget->setup = $tmpsetup;
+ return $widget;
+ }, $widgets);
+
+ $this->terminateWithSuccess($widgets);
+ }
+
+ public function listAllowed($dashboard)
+ {
+ $result = $this->WidgetModel->getForDashboard($dashboard);
+
+ $widgets = $this->getDataOrTerminateWithError($result);
+
+ $widgets = array_map(function ($widget) {
+ $widget->arguments = json_decode($widget->arguments);
+ $tmpsetup = json_decode($widget->setup);
+ $tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
+ $widget->setup = $tmpsetup;
+ return $widget;
+ }, $widgets);
+
+ $this->terminateWithSuccess($widgets);
+ }
+
+ public function setAllowed()
+ {
+ $this->load->library('form_validation');
+
+ $this->form_validation->set_rules('dashboard', 'Dashboard', 'required');
+ $this->form_validation->set_rules('widget', 'Widget', 'required');
+ $this->form_validation->set_rules('allowed', 'Allowed', 'required|is_bool');
+
+ if (!$this->form_validation->run())
+ $this->terminateWithValidationErrors($this->form_validation->error_array());
+
+ $data = [
+ 'dashboard_id' => $this->input->post('dashboard'),
+ 'widget_id' => $this->input->post('widget')
+ ];
+
+ $this->load->model('dashboard/Dashboard_Widget_model', 'DashboardWidgetModel');
+
+ if ($this->input->post('allowed'))
+ $result = $this->DashoardWidgetModel->insert($data);
+ else
+ $result = $this->DashoardWidgetModel->delete($data);
+
+ $data = $this->getDataOrTerminateWithError($result);
+
+ $this->terminateWithSuccess($data);
+ }
+}
diff --git a/application/controllers/dashboard/Widget.php b/application/controllers/dashboard/Widget.php
deleted file mode 100644
index 9966ddc12..000000000
--- a/application/controllers/dashboard/Widget.php
+++ /dev/null
@@ -1,134 +0,0 @@
- ['dashboard/benutzer:r', 'dashboard/admin:r'],
- 'getAll' => 'dashboard/admin:r',
- 'getWidgetsForDashboard' => ['dashboard/benutzer:rw', 'dashboard/admin:r'],
- 'setAllowed' => 'dashboard/admin:rw'
- )
- );
-
- $this->load->library('dashboard/DashboardLib', null, 'DashboardLib');
- $this->load->model('dashboard/Widget_model', 'WidgetModel');
- $this->load->model('dashboard/Dashboard_Widget_model', 'DashboardWidgetModel');
- }
-
- public function index()
- {
- $widget_id = $this->input->get('id');
-
- $widget = $this->WidgetModel->load($widget_id);
-
- if (isError($widget) || !getData($widget))
- return $this->outputJsonSuccess([
- "widget_id" => 0,
- "widget_kurzbz" => "notfound",
- "arguments" => [
- "className" => 'alert-danger',
- "title" => 'Widget Not Found',
- "msg" => 'The widget with the id ' . $widget_id . ' could not be found'
- ],
- "setup" => [
- "name" => 'Widget Not Found',
- "file" => absoluteJsImportUrl('public/js/components/DashboardWidget/Default.js'),
- "width" => 1,
- "height" => 1
- ]
- ]);
-
- $widget = current(getData($widget));
- $widget->arguments = json_decode($widget->arguments);
- $tmpsetup = json_decode($widget->setup);
- $tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
- $widget->setup = $tmpsetup;
-
- return $this->outputJsonSuccess($widget);
- }
-
- public function getAll()
- {
- $dashboard_id = $this->input->get('dashboard_id');
- $result = $this->WidgetModel->getWithAllowedForDashboard($dashboard_id);
-
- if (isError($result))
- return $this->outputJsonError(getError($result));
-
- $tmpwidgets = getData($result) ?: [];
- $widgets = array_map(function($widget) {
- $widget->arguments = json_decode($widget->arguments);
- $tmpsetup = json_decode($widget->setup);
- $tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
- $widget->setup = $tmpsetup;
- return $widget;
- }, $tmpwidgets);
-
- $this->outputJsonSuccess($widgets);
- }
-
- public function getWidgetsForDashboard()
- {
- $db = $this->input->get('db');
- $result = $this->WidgetModel->getForDashboard($db);
-
- if (isError($result)) {
- http_response_code(404);
- $this->terminateWithJsonError([
- 'error' => getError($result)
- ]);
- }
-
- $tmpwidgets = getData($result) ?: [];
- $widgets = array_map(function($widget) {
- $widget->arguments = json_decode($widget->arguments);
- $tmpsetup = json_decode($widget->setup);
- $tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
- $widget->setup = $tmpsetup;
- return $widget;
- }, $tmpwidgets);
-
- $this->outputJsonSuccess($widgets);
- }
-
- public function setAllowed()
- {
- $input = $this->getPostJSON();
-
- $dashboard_id = $input->dashboard_id;
- $widget_id = $input->widget_id;
- $action = $input->action;
-
- if ($action == 'add') {
- $result = $this->DashboardWidgetModel->insert([
- 'dashboard_id' => $dashboard_id,
- 'widget_id' => $widget_id
- ]);
- } elseif ($action == 'delete') {
- $result = $this->DashboardWidgetModel->delete([
- 'dashboard_id' => $dashboard_id,
- 'widget_id' => $widget_id
- ]);
- } else {
- http_response_code(404); // TODO(chris): 400?
- $this->terminateWithJsonError([
- 'error' => 'action value invalid'
- ]);
- }
- if (isError($result)) {
- http_response_code(404);
- $this->terminateWithJsonError([
- 'error' => getError($result)
- ]);
- }
- return $this->outputJsonSuccess(getData($result));
- }
-}
diff --git a/public/js/api/factory/dashboard/dashboardAdmin.js b/public/js/api/factory/dashboard/dashboardAdmin.js
index 4733d0461..4a6745866 100644
--- a/public/js/api/factory/dashboard/dashboardAdmin.js
+++ b/public/js/api/factory/dashboard/dashboardAdmin.js
@@ -41,20 +41,6 @@ export default {
url: 'api/frontend/v1/dashboard/DashboardAdmin/getAllDashboards'
};
},
- getAllWidgets(dashboard_id){
- return {
- method: 'get',
- url: 'api/frontend/v1/dashboard/DashboardAdmin/getAllWidgets',
- params: {dashboard_id}
- };
- },
- setWidgetAllowed(params){
- return {
- method: 'post',
- url: 'api/frontend/v1/dashboard/DashboardAdmin/setWidgetAllowed',
- params
- };
- },
loadFunktionen(dashboard_kurzbz){
return {
method: 'get',
diff --git a/public/js/api/factory/dashboard/widget.js b/public/js/api/factory/dashboard/widget.js
new file mode 100644
index 000000000..d7d1bbc86
--- /dev/null
+++ b/public/js/api/factory/dashboard/widget.js
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2026 fhcomplete.org
+ *
+ * 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 .
+ */
+
+export default {
+ get(widget) {
+ return {
+ method: 'get',
+ url: '/api/frontend/v1/dashboard/widget/get/' + widget
+ };
+ },
+ list(dashboard) {
+ return {
+ method: 'get',
+ url: '/api/frontend/v1/dashboard/widget/list/' + dashboard
+ };
+ },
+ listAllowed(dashboard) {
+ return {
+ method: 'get',
+ url: '/api/frontend/v1/dashboard/widget/listAllowed/' + dashboard
+ };
+ },
+ setAllowed(dashboard_id, widget_id, allowed) {
+ return {
+ method: 'post',
+ url: '/api/frontend/v1/dashboard/widget/setAllowed',
+ params: {
+ dashboard_id, widget_id, allowed
+ }
+ };
+ }
+};
\ No newline at end of file
diff --git a/public/js/components/Dashboard/Admin/Widgets.js b/public/js/components/Dashboard/Admin/Widgets.js
index 60ad6e1b8..203be9d9c 100644
--- a/public/js/components/Dashboard/Admin/Widgets.js
+++ b/public/js/components/Dashboard/Admin/Widgets.js
@@ -1,4 +1,4 @@
-import ApiDashboardAdmin from "../../../api/factory/dashboard/dashboardAdmin.js";
+import ApiDashboardWidget from "../../../api/factory/dashboard/Widget.js";
export default {
emits: [
@@ -12,25 +12,16 @@ export default {
methods: {
sendChange(widget_id) {
let allow = !this.widgets.find(el => el.widget_id == widget_id).allowed;
- const params = {
- dashboard_id: this.dashboard_id,
- widget_id,
- action: allow ? 'add' : 'delete'
- };
this.$api
- .call(ApiDashboardAdmin.setWidgetAllowed(params))
+ .call(ApiDashboardWidget.setAllowed(this.dashboard_id, widget_id, allow))
.catch(this.$fhcAlert.handleSystemError);
}
},
created() {
this.$api
- .call(ApiDashboardAdmin.getAllWidgets(this.dashboard_id))
+ .call(ApiDashboardWidget.list(this.dashboard_id))
.then(result => {
-/* console.log(result.data.map(el => ({
- ...el,
- ...{setup:JSON.parse(el.setup),arguments:JSON.parse(el.arguments),allowed:!!el.allowed}
- })));*/
this.$emit('assignWidgets', result.data.map(el => ({
...el,
...{setup:JSON.parse(el.setup),arguments:JSON.parse(el.arguments),allowed:!!el.allowed}
diff --git a/public/js/components/Dashboard/Dashboard.js b/public/js/components/Dashboard/Dashboard.js
index c27f0c405..3ed8aac09 100644
--- a/public/js/components/Dashboard/Dashboard.js
+++ b/public/js/components/Dashboard/Dashboard.js
@@ -2,6 +2,8 @@ import DashboardSection from "./Section.js";
import DashboardWidgetPicker from "./Widget/Picker.js";
import ObjectUtils from "../../helpers/ObjectUtils.js";
+import ApiDashboardWidget from '../../api/factory/dashboard/widget.js';
+
export default {
name: 'Dashboard',
components: {
@@ -25,14 +27,14 @@ export default {
data() {
return {
sections: [],
- widgets: null,
+ widgetsSetup: null,
editMode: false,
}
},
provide() {
return {
editMode: Vue.computed(()=>this.editMode),
- widgetsSetup: Vue.computed(() => this.widgets),
+ widgetsSetup: Vue.computed(() => this.widgetsSetup),
timezone: Vue.computed(() => this.viewData.timezone)
}
},
@@ -43,17 +45,6 @@ export default {
},
methods: {
widgetAdd(section_name, widget) {
- if (this.widgets === null) {
- axios.get(this.apiurl + '/Widget/getWidgetsForDashboard', {params:{
- db: this.dashboard
- }}).then(res => {
- res.data.retval.forEach(widget => {
- widget.arguments = JSON.parse(widget.arguments);
- widget.setup = JSON.parse(widget.setup);
- });
- this.widgets = res.data.retval;
- }).catch(err => console.error('ERROR:', err));
- }
this.$refs.widgetpicker.getWidget().then(widget_id => {
widget.widget = widget_id;
widget.id = 'loading_' + String((new Date()).valueOf());
@@ -143,13 +134,13 @@ export default {
},
created() {
this.$p.loadCategory('dashboard');
- axios.get(this.apiurl + '/Widget/getWidgetsForDashboard', {
- params: {
- db: this.dashboard
- }
- }).then(res => {
- this.widgets = res.data.retval;
- }).catch(err => console.error('ERROR:', err));
+
+ this.$api
+ .call(ApiDashboardWidget.listAllowed(this.dashboard))
+ .then(res => {
+ this.widgetsSetup = res.data;
+ })
+ .catch(this.$fhcAlert.handleSystemError);
axios.get(this.apiurl + '/Config', {params:{
db: this.dashboard
@@ -186,6 +177,6 @@ export default {
-
+
`
}
diff --git a/public/js/components/Dashboard/Item.js b/public/js/components/Dashboard/Item.js
index 06a03ae3a..1fe67ab45 100644
--- a/public/js/components/Dashboard/Item.js
+++ b/public/js/components/Dashboard/Item.js
@@ -1,5 +1,5 @@
import BsModal from "../Bootstrap/Modal.js";
-import CachedWidgetLoader from "../../composables/Dashboard/CachedWidgetLoader.js";
+import { useCachedWidgetLoader } from "../../composables/Dashboard/CachedWidgetLoader.js";
import HeightTransition from "../Tranistion/HeightTransition.js";
export default {
@@ -142,8 +142,14 @@ export default {
this.isLoading = false;
},
},
+ setup() {
+ const { actions } = useCachedWidgetLoader();
+ return {
+ loadWidget: actions.load
+ };
+ },
async created() {
- this.widget = await CachedWidgetLoader.loadWidget(this.id);
+ this.widget = await this.loadWidget(this.id);
let component = (await import(this.widget.setup.file)).default;
this.$options.components["widget" + this.widget.widget_id] = component;
this.component = "widget" + this.widget.widget_id;
diff --git a/public/js/components/Dashboard/Section.js b/public/js/components/Dashboard/Section.js
index 75cfe8e85..817cc52a3 100644
--- a/public/js/components/Dashboard/Section.js
+++ b/public/js/components/Dashboard/Section.js
@@ -1,7 +1,7 @@
import BsConfirm from "../Bootstrap/Confirm.js";
import DropGrid from '../Drop/Grid.js'
import DashboardItem from "./Item.js";
-import CachedWidgetLoader from "../../composables/Dashboard/CachedWidgetLoader.js";
+import { useCachedWidgetLoader } from "../../composables/Dashboard/CachedWidgetLoader.js";
import WidgetIcon from "./Widget/WidgetIcon.js"
export default {
@@ -125,23 +125,23 @@ export default {
},
checkResizeLimit(item, w, h) {
// NOTE(chris): widgets needs to be loaded for this to work
- let widget = CachedWidgetLoader.getWidget(item.widget);
+ let widget = this.widgetState[item.widget];
if (widget) {
- let minmaxW = widget.setup.width;
+ let minmaxW = { ...widget.setup.width };
if (minmaxW.max)
minmaxW.min = minmaxW.min || 1;
else
- minmaxW = {min:minmaxW,max:minmaxW};
+ minmaxW = { min: minmaxW, max: minmaxW };
if (w < minmaxW.min)
w = minmaxW.min;
if (w > minmaxW.max)
w = minmaxW.max;
- let minmaxH = widget.setup.height;
+ let minmaxH = { ...widget.setup.height };
if (minmaxH.max)
minmaxH.min = minmaxH.min || 1;
else
- minmaxH = {min:minmaxH,max:minmaxH};
+ minmaxH = { min: minmaxH, max: minmaxH };
if (h < minmaxH.min)
h = minmaxH.min;
if (h > minmaxH.max)
@@ -199,6 +199,13 @@ export default {
this.$emit('widgetUpdate', this.name, payload);
}
},
+ setup() {
+ const { state: widgetState } = useCachedWidgetLoader();
+
+ return {
+ widgetState
+ };
+ },
mounted() {
let self = this;
let cont = self.$refs.container;
diff --git a/public/js/composables/Dashboard/CachedWidgetLoader.js b/public/js/composables/Dashboard/CachedWidgetLoader.js
index a92e3e557..4bc2d4992 100644
--- a/public/js/composables/Dashboard/CachedWidgetLoader.js
+++ b/public/js/composables/Dashboard/CachedWidgetLoader.js
@@ -1,29 +1,36 @@
-let __widgets = {};
-let __widgetsStarted = {};
-let __path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/dashboard/Widget';
+import ApiWidget from "../../api/factory/dashboard/widget.js";
-export default {
- getWidget(id) {
- return __widgets[id];
- },
- loadWidget(id) {
- if (__widgets[id])
- return Promise.resolve(__widgets[id]);
- if (__widgetsStarted[id])
- return __widgetsStarted[id];
- if (!__path)
- return Promise.reject('Widget could not be loaded because there is no path yet!');
+const promises = Vue.ref([]);
+const stateRef = Vue.ref([]);
+const state = Vue.readonly(stateRef);
- __widgetsStarted[id] = new Promise((resolve, reject) => {
- axios.get(__path, {params:{id}}).then(res => {
- __widgets[id] = res.data.retval;
- __widgetsStarted[id] = undefined;
- resolve(__widgets[id]);
- }).catch(error => reject(error.response.data.retval.error));
- });
- return __widgetsStarted[id];
- },
- setPath(path) {
- __path = path;
+export function useCachedWidgetLoader() {
+ const $api = Vue.inject('$api');
+ const $fhcAlert = Vue.inject('$fhcAlert');
+
+ function load(id) {
+ if (state.value[id])
+ return Promise.resolve(state.value[id]);
+
+ if (!promises.value[id])
+ promises.value[id] = new Promise((resolve, reject) => {
+ $api
+ .call(ApiWidget.get(id))
+ .then(res => {
+ stateRef.value[id] = res.data;
+ promises.value[id] = undefined;
+ resolve(state.value[id]);
+ })
+ .catch($fhcAlert.handleSystemError);
+ });
+
+ return promises.value[id];
}
+
+ return {
+ state,
+ actions: {
+ load
+ }
+ };
}
\ No newline at end of file