diff --git a/public/js/components/Dashboard/Admin.js b/public/js/components/Dashboard/Admin.js
new file mode 100644
index 000000000..775cd87d6
--- /dev/null
+++ b/public/js/components/Dashboard/Admin.js
@@ -0,0 +1,113 @@
+import BsPrompt from "../Bootstrap/Prompt.js";
+import DashboardAdminEdit from "./Admin/Edit.js";
+import DashboardAdminWidgets from "./Admin/Widgets.js";
+import DashboardAdminPresets from "./Admin/Presets.js";
+
+export default {
+ components: {
+ DashboardAdminEdit,
+ DashboardAdminWidgets,
+ DashboardAdminPresets
+ },
+ provide() {
+ return {
+ adminMode: true
+ };
+ },
+ data() {
+ return {
+ dashboards: [],
+ current: -1,
+ widgets: []
+ };
+ },
+ computed: {
+ apiurl() {
+ return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/dashboard';
+ },
+ dashboard() {
+ return this.dashboards.find(el => el.dashboard_id == this.current);
+ }
+ },
+ methods: {
+ dashboardAdd() {
+ let _name = '';
+ BsPrompt.popup('New Dashboard name').then(
+ name => {
+ _name = name;
+ return axios.post(this.apiurl + '/Dashboard/Create', {
+ dashboard_kurzbz: name
+ })
+ }
+ ).then(res => {
+ let newDashboard = {
+ dashboard_id: res.data.retval,
+ dashboard_kurzbz: _name,
+ beschreibung: ''
+ };
+ this.dashboards.push(newDashboard);
+ this.current = newDashboard.dashboard_id;
+ }).catch(err => err !== undefined ? console.error('ERROR:', err) : 0);
+ },
+ dashboardUpdate(dashboard) {
+ // TODO(chris): Loading or message
+ axios.post(this.apiurl + '/Dashboard/Update', dashboard).then(() => {
+ let old = this.dashboards.find(el => el.dashboard_id == dashboard.dashboard_id);
+ old.dashboard_kurzbz = dashboard.dashboard_kurzbz;
+ old.beschreibung = dashboard.beschreibung;
+ }).catch(err => console.error('ERROR:', err));
+ },
+ dashboardDelete(dashboard_id) {
+ axios.post(this.apiurl + '/Dashboard/Delete', {dashboard_id}).then(() => {
+ this.current = -1;
+ this.dashboards = this.dashboards.filter(el => el.dashboard_id != dashboard_id);
+ }).catch(err => console.error('ERROR:', err));
+ },
+ assignWidgets(widgets) {
+ this.widgets = widgets;
+ /*while (this.widgets.length)
+ this.widgets.pop();
+ for (var i in widgets)
+ this.widgets.push(widgets[i]);*/
+ }
+ },
+ created() {
+ axios.get(this.apiurl + '/Dashboard').then(res => {
+ //console.log(res.data.retval);
+ this.dashboards = res.data.retval;
+ }).catch(err => console.error('ERROR:', err));
+ },
+ template: `
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+
`
+}
diff --git a/public/js/components/Dashboard/Admin/Edit.js b/public/js/components/Dashboard/Admin/Edit.js
new file mode 100644
index 000000000..ec841a9ad
--- /dev/null
+++ b/public/js/components/Dashboard/Admin/Edit.js
@@ -0,0 +1,38 @@
+import BsConfirm from '../../Bootstrap/Confirm.js';
+
+export default {
+ emits: [
+ "change",
+ "delete"
+ ],
+ props: {
+ dashboard_id: Number,
+ dashboard_kurzbz: String,
+ beschreibung: String
+ },
+ data() {
+ return {
+ kurzbz: this.dashboard_kurzbz,
+ desc: this.beschreibung
+ }
+ },
+ methods: {
+ sendDelete() {
+ BsConfirm.popup('Sure?').then(() => this.$emit('delete', this.dashboard_id)).catch();
+ }
+ },
+ template: `
+
+
+
+
+
+
+
+
+
+
+
+
+
`
+}
diff --git a/public/js/components/Dashboard/Admin/Presets.js b/public/js/components/Dashboard/Admin/Presets.js
new file mode 100644
index 000000000..19052171f
--- /dev/null
+++ b/public/js/components/Dashboard/Admin/Presets.js
@@ -0,0 +1,159 @@
+import DashboardSection from "../Section.js";
+import DashboardWidgetPicker from "../Widget/Picker.js";
+import ObjectUtils from "../../../composables/ObjectUtils.js";
+
+export default {
+ components: {
+ DashboardSection,
+ DashboardWidgetPicker
+ },
+ props: {
+ dashboard: String,
+ widgets: Array
+ },
+ data: () => ({
+ funktionen: {},
+ sections: [],
+ }),
+ computed: {
+ apiurl() {
+ return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/dashboard';
+ },
+ pickerWidgets() {
+ return this.widgets.filter(widget => widget.allowed);
+ }
+ },
+ methods: {
+ widgetAdd(section_name, widget) {
+ this.$refs.widgetpicker.getWidget().then(widget_id => {
+ widget.widget = widget_id;
+ let loading = {...widget};
+ loading.loading = true;
+ this.sections.forEach(section => {
+ if (section.name == section_name)
+ section.widgets.push(loading);
+ });
+
+ axios.post(this.apiurl + '/Config/addWidgetsToPreset', {
+ db: this.dashboard,
+ funktion_kurzbz: section_name,
+ widgets: [widget]
+ }).then(result => {
+ let newId = Object.keys(result.data.retval.data.widgets[section_name]).pop();
+ widget.id = newId;
+ this.sections.forEach(section => {
+ if (section.name == section_name) {
+ section.widgets.splice(section.widgets.indexOf(loading),1);
+ section.widgets.push(widget);
+ }
+ });
+ }).catch(error => {
+ console.error('ERROR: ', error);
+ alert('ERROR: ' + error.response.data.retval);
+ });
+ });
+ },
+ widgetUpdate(section_name, payload) {
+ payload = payload[section_name];
+ for (var k in payload) {
+ for (var i in this.sections) {
+ if (this.sections[i].name == section_name) {
+ for (var wid in this.sections[i].widgets) {
+ if (this.sections[i].widgets[wid].id == k) {
+ payload[k] = ObjectUtils.mergeDeep(this.sections[i].widgets[wid], payload[k]);
+ // NOTE(chris): remove internal props
+ for (var prop in {_x:1,_y:1,_w:1,_h:1,index:1,id:1})
+ if (payload[k][prop])
+ delete payload[k][prop];
+ break;
+ }
+ }
+ break;
+ }
+ }
+ payload[k].widgetid = k;
+ delete payload[k].custom;
+ }
+ axios.post(this.apiurl + '/Config/addWidgetsToPreset', {
+ db: this.dashboard,
+ funktion_kurzbz: section_name,
+ widgets: payload
+ }).then(() => {
+ this.sections.forEach(section => {
+ if (section.name == section_name) {
+ section.widgets.forEach((widget, i) => {
+ if (payload[widget.id]) {
+ payload[widget.id].id = widget.id;
+ payload[widget.id].index = widget.index;
+ section.widgets[i] = payload[widget.id];
+ section.widgets[i].custom = 1;
+ }
+ });
+ }
+ });
+ }).catch(error => {
+ // TODO(chris): revert placement on failure
+ console.error('ERROR: ', error);
+ alert('ERROR: ' + error.response.data.retval);
+ });
+ },
+ widgetRemove(section_name, id) {
+ axios.post(this.apiurl + '/Config/removeWidgetFromPreset', {
+ db: this.dashboard,
+ funktion_kurzbz: section_name,
+ widgetid: id
+ }).then(() => {
+ this.sections.forEach(section => {
+ if (section.name == section_name)
+ section.widgets = section.widgets.filter(widget => widget.id != id);
+ });
+ }).catch(error => {
+ console.error('ERROR: ', error);
+ alert('ERROR: ' + error.response.data.retval);
+ });
+ },
+ loadSections(evt) {
+ let funktionen = Array.from(evt.target.querySelectorAll("option:checked"),e=>e.value);
+ this.sections = [];
+ axios.get(this.apiurl + '/Config/PresetBatch', {params: {
+ db: this.dashboard,
+ funktionen
+ }}).then(res => {
+ for (var section in res.data.retval) {
+ let widgets = [];
+ for (var wid in res.data.retval[section]) {
+ res.data.retval[section][wid].id = wid;
+ res.data.retval[section][wid].custom = 1;
+ widgets.push(res.data.retval[section][wid]);
+ }
+ this.sections.push({
+ name: section,
+ widgets
+ });
+ }
+ }).catch(err => console.error('ERROR:', err));
+ }
+ },
+ created() {
+ axios.get(this.apiurl + '/Config/Funktionen').then(res => {
+ //console.log(res.data.retval);
+ this.funktionen = {general: 'GENERAL'};
+ res.data.retval.forEach(funktion => {
+ this.funktionen[funktion.funktion_kurzbz] = funktion.beschreibung;
+ });
+ }).catch(err => console.error('ERROR:', err));
+ },
+ template: `
+
+
+
+
+
+
+
+
+
+
`
+}
diff --git a/public/js/components/Dashboard/Admin/Widgets.js b/public/js/components/Dashboard/Admin/Widgets.js
new file mode 100644
index 000000000..34b7b482c
--- /dev/null
+++ b/public/js/components/Dashboard/Admin/Widgets.js
@@ -0,0 +1,45 @@
+export default {
+ emits: [
+ "change",
+ "assignWidgets"
+ ],
+ props: {
+ dashboard_id: Number,
+ widgets: Array
+ },
+ computed: {
+ apiurl() {
+ return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/dashboard';
+ }
+ },
+ methods: {
+ sendChange(widget_id) {
+ let allow = !this.widgets.find(el => el.widget_id == widget_id).allowed;
+ axios.post(this.apiurl + '/Widget/setAllowed', {
+ dashboard_id: this.dashboard_id,
+ widget_id,
+ action: allow ? 'add' : 'delete'
+ }).catch(err => console.error('ERROR: ' + err));
+ }
+ },
+ created() {
+ axios.get(this.apiurl + '/Widget/getAll', {
+ params:{
+ dashboard_id: this.dashboard_id
+ }
+ }).then(
+ result => {
+ this.$emit('assignWidgets', result.data.retval.map(el => ({
+ ...el,
+ ...{setup:JSON.parse(el.setup),arguments:JSON.parse(el.arguments),allowed:!!el.allowed}
+ })));
+ }
+ ).catch(err => console.error('ERROR:', err));
+ },
+ template: ``
+}