mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-10-12 15:04:04 +00:00
Widget admistration (first draft)
This commit is contained in:
@@ -170,13 +170,6 @@ $config['navigation_header'] = array(
|
||||
'expand' => true,
|
||||
'sort' => 51,
|
||||
'requiredPermissions' => 'vertrag/mitarbeiter:r'
|
||||
),
|
||||
'studierendenverwaltung' => array(
|
||||
'link' => site_url('studentenverwaltung'),
|
||||
'description' => 'Studierendenverwaltung',
|
||||
'expand' => true,
|
||||
'sort' => 52,
|
||||
'requiredPermissions' => ['admin:r', 'assistenz:r']
|
||||
)
|
||||
)
|
||||
),
|
||||
@@ -385,8 +378,21 @@ $config['navigation_menu']['apps'] = [
|
||||
],
|
||||
'lav' => [
|
||||
'link' => site_url('lehre/lehrauftrag/Lehrauftrag/Dashboard'),
|
||||
'description' => 'Lehrauftragsverwaltung',
|
||||
'description' => 'Lehraufträge',
|
||||
#'icon' => 'person-chalkboard',
|
||||
'requiredPermissions' => array('lehre/lehrauftrag_bestellen:r', 'lehre/lehrauftrag_erteilen:r')
|
||||
]
|
||||
];
|
||||
|
||||
$config['navigation_menu']['dashboard/*'] = [
|
||||
'dashboards' => [
|
||||
'link' => site_url('dashboard/Admin'),
|
||||
'description' => 'Dashboard',
|
||||
'requiredPermissions' => 'dashboard/admin:rw'
|
||||
],
|
||||
'widgets' => [
|
||||
'link' => site_url('dashboard/Admin/widgets'),
|
||||
'description' => 'Widgets',
|
||||
'requiredPermissions' => 'dashboard/admin:rw'
|
||||
]
|
||||
];
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
use \DirectoryIterator as DirectoryIterator;
|
||||
|
||||
/**
|
||||
* This controller operates between (interface) the JS (GUI) and the back-end
|
||||
* Provides data to the ajax get calls about the users dashboard
|
||||
@@ -31,7 +33,12 @@ class Widget extends FHCAPI_Controller
|
||||
'get' => ['dashboard/benutzer:r', 'dashboard/admin:r'],
|
||||
'list' => 'dashboard/admin:r',
|
||||
'listAllowed' => ['dashboard/benutzer:rw', 'dashboard/admin:r'],
|
||||
'setAllowed' => 'dashboard/admin:rw'
|
||||
'listAll' => 'dashboard/admin:r',
|
||||
'listAllOriginal' => 'dashboard/admin:rw',
|
||||
'setAllowed' => 'dashboard/admin:rw',
|
||||
'create' => 'dashboard/admin:rw',
|
||||
'update' => 'dashboard/admin:rw',
|
||||
'generators' => 'dashboard/admin:rw',
|
||||
]);
|
||||
|
||||
// Libraries
|
||||
@@ -107,6 +114,38 @@ class Widget extends FHCAPI_Controller
|
||||
$this->terminateWithSuccess($widgets);
|
||||
}
|
||||
|
||||
public function listAll()
|
||||
{
|
||||
$result = $this->WidgetModel->load();
|
||||
|
||||
$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 listAllOriginal()
|
||||
{
|
||||
$result = $this->WidgetModel->load();
|
||||
|
||||
$widgets = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$widgets = array_map(function ($widget) {
|
||||
$widget->arguments = json_decode($widget->arguments);
|
||||
$widget->setup = json_decode($widget->setup);
|
||||
return $widget;
|
||||
}, $widgets);
|
||||
|
||||
$this->terminateWithSuccess($widgets);
|
||||
}
|
||||
|
||||
public function setAllowed()
|
||||
{
|
||||
$this->load->library('form_validation');
|
||||
@@ -134,4 +173,149 @@ class Widget extends FHCAPI_Controller
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$this->loadPhrases(['mobility', 'dashboard']);
|
||||
$this->load->library('form_validation');
|
||||
|
||||
$this->form_validation->set_rules(
|
||||
'widget_kurzbz',
|
||||
$this->p->t('mobility', 'kurzbz'),
|
||||
'required|is_not_in_db[dashboard/Widget_model:widget_kurzbz]',
|
||||
[
|
||||
'is_not_in_db' => 'TODO(chris): error phrase'
|
||||
]
|
||||
);
|
||||
$this->form_validation->set_rules(
|
||||
'setup[generator]',
|
||||
$this->p->t('dashboard', 'generator'),
|
||||
'required'
|
||||
);
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
$setup = $this->input->post('setup');
|
||||
|
||||
$file = explode(':', $setup['generator']);
|
||||
if (count($file) == 1) {
|
||||
$setup['file'] = 'public/js/components/DashboardWidget/' . $file[0] . '.js';
|
||||
} else {
|
||||
$setup['file'] = 'public/extensions/' . $file[0] . '/js/components/DashboardWidget/' . $file[1] . '.js';
|
||||
}
|
||||
|
||||
$data = [
|
||||
'widget_kurzbz' => $this->input->post('widget_kurzbz'),
|
||||
'setup' => json_encode($setup),
|
||||
'arguments' => json_encode([]),
|
||||
];
|
||||
$result = $this->WidgetModel->insert($data);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
$this->loadPhrases(['zeitaufzeichnung']);
|
||||
$this->load->library('form_validation');
|
||||
|
||||
$this->form_validation->set_rules(
|
||||
'widget_id',
|
||||
$this->p->t('zeitaufzeichnung', 'id'),
|
||||
'required'
|
||||
);
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
$widget_id = $this->input->post('widget_id');
|
||||
$data = [];
|
||||
foreach ([
|
||||
'widget_kurzbz',
|
||||
'beschreibung',
|
||||
'setup',
|
||||
'arguments',
|
||||
'berechtigung_kurzbz',
|
||||
] as $post) {
|
||||
$value = $this->input->post($post);
|
||||
if ($value) {
|
||||
if ($post == 'setup' || $post == 'arguments')
|
||||
$value = json_encode($value);
|
||||
$data[$post] = $value;
|
||||
}
|
||||
}
|
||||
if (!$data)
|
||||
$this->terminateWithSuccess();
|
||||
|
||||
$result = $this->WidgetModel->update($widget_id, $data);
|
||||
|
||||
$this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
|
||||
public function generators()
|
||||
{
|
||||
$result = $this->getGeneratorsRecursive();
|
||||
|
||||
$this->load->library('ExtensionsLib');
|
||||
$extensions = $this->extensionslib->getInstalledExtensions();
|
||||
if (hasData($extensions)) {
|
||||
foreach (getData($extensions) as $extension) {
|
||||
$result = array_merge($result, $this->getGeneratorsRecursive($extension->name));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->terminateWithSuccess($result);
|
||||
}
|
||||
|
||||
protected function getGeneratorsRecursive($extension = '', $path = '')
|
||||
{
|
||||
$result = [];
|
||||
|
||||
$dashboard_widget_path = 'public/js/components/DashboardWidget/';
|
||||
|
||||
$name = '';
|
||||
$file_path = $dashboard_widget_path . $path;
|
||||
$generator_path = $dashboard_widget_path . 'Generators/' . $path;
|
||||
|
||||
if ($extension) {
|
||||
$name = $extension . ':';
|
||||
$file_path = APPPATH . 'extensions/' . $extension . '/' . $file_path;
|
||||
$generator_path = APPPATH . 'extensions/' . $extension . '/' . $generator_path;
|
||||
} else {
|
||||
$file_path = FHCPATH . $file_path;
|
||||
$generator_path = FHCPATH . $generator_path;
|
||||
}
|
||||
|
||||
$name .= $path;
|
||||
|
||||
$generator_path = str_replace('/', DIRECTORY_SEPARATOR, $generator_path);
|
||||
|
||||
if (is_dir($generator_path)) {
|
||||
$dir = new DirectoryIterator($generator_path);
|
||||
|
||||
foreach ($dir as $file) {
|
||||
if ($file->isDot())
|
||||
continue;
|
||||
$filename = $file->getFilename();
|
||||
if ($file->isDir()) {
|
||||
if (is_dir(str_replace('/', DIRECTORY_SEPARATOR, $file_path . $filename))) {
|
||||
$res = $this->getGeneratorsRecursive($extension, $path . $filename . '/');
|
||||
$result = array_merge($result, $res);
|
||||
}
|
||||
} else {
|
||||
if (file_exists(str_replace('/', DIRECTORY_SEPARATOR, $file_path . $filename))) {
|
||||
if ($file->getExtension() == 'js')
|
||||
$result[] = $name . $file->getBasename('.js');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ class Admin extends Auth_Controller
|
||||
parent::__construct(
|
||||
array(
|
||||
'index' => 'dashboard/admin:rw',
|
||||
'widgets' => 'dashboard/admin:rw',
|
||||
'preview' => 'dashboard/admin:r',
|
||||
)
|
||||
);
|
||||
@@ -43,6 +44,11 @@ class Admin extends Auth_Controller
|
||||
$this->load->view('dashboard/admin.php', []);
|
||||
}
|
||||
|
||||
public function widgets()
|
||||
{
|
||||
$this->load->view('dashboard/widgets.php', [9]);
|
||||
}
|
||||
|
||||
public function preview($dashboard_kurzbz = 'CIS')
|
||||
{
|
||||
$this->load->view('dashboard/preview.php', [
|
||||
|
||||
@@ -529,6 +529,17 @@ function is_in_db($key, $model = '')
|
||||
return (isSuccess($result) && hasData($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* check if an entry does not exist in the database
|
||||
*/
|
||||
function is_not_in_db($key, $model = '')
|
||||
{
|
||||
if (!$model)
|
||||
return false;
|
||||
|
||||
return !is_in_db($key, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* is building an array for Dropdown Entry in Print Dropdown
|
||||
* @param $id id for the Document to add to the Document Array
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
$this->load->view(
|
||||
'templates/FHC-Header',
|
||||
array(
|
||||
'title' => 'FH-Complete',
|
||||
'bootstrap5' => true,
|
||||
'fontawesome6' => true,
|
||||
'axios027' => true,
|
||||
'restclient' => true,
|
||||
'vue3' => true,
|
||||
'tabulator6' => true,
|
||||
'primevue3' => true,
|
||||
'vuedatepicker11' => true,
|
||||
'customJSs' => [
|
||||
'vendor/moment/luxonjs/luxon.min.js'
|
||||
],
|
||||
'customJSModules' => ['public/js/apps/Dashboard/WidgetAdmin.js'],
|
||||
'customCSSs' => [
|
||||
'public/css/Fhc.css',
|
||||
'public/css/components/verticalsplit.css',
|
||||
'public/css/components/dashboard.css',
|
||||
'public/css/components/primevue.css',
|
||||
'public/css/components/vue-datepicker.css',
|
||||
],
|
||||
'navigationcomponent' => true
|
||||
)
|
||||
);
|
||||
?>
|
||||
|
||||
<div id="main"></div>
|
||||
|
||||
<?php $this->load->view('templates/FHC-Footer'); ?>
|
||||
+25
-2
@@ -1,3 +1,26 @@
|
||||
.fhc-page-grid {
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
grid: "header header" auto "nav main" 1fr / auto 1fr;
|
||||
}
|
||||
.fhc-page-grid > * {
|
||||
grid-area: header;
|
||||
}
|
||||
.fhc-page-grid > .navbar-left-side {
|
||||
grid-area: nav;
|
||||
position: initial;
|
||||
align-items: start;
|
||||
}
|
||||
.fhc-page-grid > .content {
|
||||
grid-area: main;
|
||||
margin: 0;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.fhc-page-grid {
|
||||
grid: "header main" auto "nav main" 1fr / auto 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.fhc-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -100,10 +123,10 @@
|
||||
}
|
||||
|
||||
.modal-msg {
|
||||
max-width: 1378px;
|
||||
max-width: 1378px;
|
||||
}
|
||||
.modal-msg .modal-content {
|
||||
height: 95vh;
|
||||
height: 95vh;
|
||||
}
|
||||
|
||||
.fhcSkipLink {
|
||||
|
||||
@@ -34,6 +34,18 @@ export default {
|
||||
url: '/api/frontend/v1/dashboard/widget/listAllowed/' + dashboard
|
||||
};
|
||||
},
|
||||
listAll() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/dashboard/widget/listAll'
|
||||
};
|
||||
},
|
||||
listAllOriginal() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/dashboard/widget/listAllOriginal'
|
||||
};
|
||||
},
|
||||
setAllowed(dashboard_id, widget_id, allowed) {
|
||||
return {
|
||||
method: 'post',
|
||||
@@ -42,5 +54,25 @@ export default {
|
||||
dashboard_id, widget_id, allowed
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
create(params) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/dashboard/widget/create',
|
||||
params
|
||||
};
|
||||
},
|
||||
update(params) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/dashboard/widget/update',
|
||||
params
|
||||
};
|
||||
},
|
||||
generators() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/dashboard/widget/generators'
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import { CoreNavigationCmpt } from '../../components/navigation/Navigation.js';
|
||||
import WidgetAdmin from '../../components/Dashboard/WidgetAdmin.js';
|
||||
|
||||
import PluginsPhrasen from '../../plugins/Phrasen.js';
|
||||
|
||||
const app = Vue.createApp({
|
||||
name: 'WidgetsAdminApp',
|
||||
data: () => ({
|
||||
appSideMenuEntries: {}
|
||||
}),
|
||||
components: {
|
||||
CoreNavigationCmpt,
|
||||
WidgetAdmin
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone
|
||||
};
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="widgets-admin-app fhc-page-grid">
|
||||
<core-navigation-cmpt :add-side-menu-entries="appSideMenuEntries" />
|
||||
|
||||
<div class="content d-flex flex-column gap-3 w-100 h-100 overflow-hidden">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3">
|
||||
<h1 class="h2 pb-3 border-bottom mb-0 w-100">Widgets</h1>
|
||||
</div>
|
||||
<widget-admin class="h-100 overflow-hidden" />
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
app.use(primevue.config.default, {
|
||||
zIndex: {
|
||||
overlay: 9000,
|
||||
tooltip: 8000
|
||||
}
|
||||
})
|
||||
app.use(PluginsPhrasen);
|
||||
app.directive('tooltip', primevue.tooltip);
|
||||
app.mount('#main');
|
||||
@@ -0,0 +1,77 @@
|
||||
import VerticalSplit from "../verticalsplit/verticalsplit.js";
|
||||
import WidgetNew from "./WidgetAdmin/New.js";
|
||||
import WidgetList from "./WidgetAdmin/List.js";
|
||||
import WidgetEdit from "./WidgetAdmin/Edit.js";
|
||||
|
||||
export default {
|
||||
name: 'WidgetAdmin',
|
||||
components: {
|
||||
VerticalSplit,
|
||||
WidgetNew,
|
||||
WidgetList,
|
||||
WidgetEdit,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
originalData: null,
|
||||
currentData: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
unsavedProgress() {
|
||||
if (JSON.stringify(this.originalData) != JSON.stringify(this.currentData))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
select(data) {
|
||||
this.originalData = data;
|
||||
this.currentData = JSON.parse(JSON.stringify(data));
|
||||
},
|
||||
create(data) {
|
||||
// TODO(chris): modify data with base info
|
||||
this.currentData = JSON.parse(JSON.stringify(data));
|
||||
this.save();
|
||||
},
|
||||
save() {
|
||||
this.select(this.currentData);
|
||||
this.$nextTick(() => {
|
||||
this.$refs.list.$refs.table.tabulator
|
||||
.updateOrAddData([this.originalData])
|
||||
.then(res => {
|
||||
res[0].select();
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
});
|
||||
},
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="widgets-admin">
|
||||
<widget-new ref="new" @create="create" />
|
||||
<vertical-split class="h-100 position-relative" use-div-height>
|
||||
<template #top>
|
||||
<widget-list
|
||||
ref="list"
|
||||
:unsaved-progress="unsavedProgress"
|
||||
@new="$refs.new?.show"
|
||||
@select="select"
|
||||
/>
|
||||
</template>
|
||||
<template #bottom>
|
||||
<widget-edit
|
||||
v-if="currentData"
|
||||
ref="edit"
|
||||
v-model="currentData"
|
||||
:original-data="originalData"
|
||||
:unsaved-progress="unsavedProgress"
|
||||
@saved="save"
|
||||
/>
|
||||
<div v-else class="h-100 d-flex justify-content-center align-items-center">
|
||||
Please select a widget
|
||||
</div>
|
||||
</template>
|
||||
</vertical-split>
|
||||
</div>`
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import CoreForm from "../../Form/Form.js";
|
||||
import EditBasics from "./Edit/Basics.js";
|
||||
|
||||
import ApiWidget from "../../../api/factory/dashboard/widget.js";
|
||||
|
||||
export default {
|
||||
name: 'WidgetsAdminEdit',
|
||||
components: {
|
||||
CoreForm,
|
||||
EditBasics,
|
||||
},
|
||||
props: {
|
||||
originalData: Object,
|
||||
modelValue: Object,
|
||||
unsavedProgress: Boolean,
|
||||
},
|
||||
emits: [
|
||||
"saved",
|
||||
"update:modelValue",
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
generator: null,
|
||||
saving: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
'originalData.setup.generator': {
|
||||
async handler(gen) {
|
||||
if (!gen)
|
||||
return this.generator = null;
|
||||
|
||||
// TODO(chris): extensions
|
||||
let file = '../../DashboardWidget/Generators/' + gen + '.js';
|
||||
|
||||
this.generator = Vue.markRaw((await import(file)).default);
|
||||
},
|
||||
immediate: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
this.saving = true;
|
||||
this.$refs.form.clearValidation();
|
||||
const data = JSON.parse(JSON.stringify(this.modelValue));
|
||||
this.$refs.form
|
||||
.call(ApiWidget.update(data))
|
||||
.then(() => {
|
||||
this.$emit('update:modelValue', data);
|
||||
this.$emit('saved');
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError)
|
||||
.finally(() => this.saving = false);
|
||||
},
|
||||
},
|
||||
template: /* html */`
|
||||
<core-form
|
||||
v-if="modelValue"
|
||||
ref="form"
|
||||
class="widgets-admin-edit mx-2"
|
||||
@submit.prevent="save"
|
||||
>
|
||||
<edit-basics v-model="modelValue" :original="originalData" />
|
||||
<template v-if="generator">
|
||||
<component :is="generator" v-model="modelValue" :original="originalData" :key="modelValue.widget_id" />
|
||||
</template>
|
||||
<div class="position-absolute bottom-0 end-0 z-1">
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="saving || !unsavedProgress"
|
||||
class="btn btn-primary"
|
||||
>{{ $p.t('ui/speichern') }}</button>
|
||||
</div>
|
||||
</core-form>
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import FormInput from "../../../Form/Input.js";
|
||||
|
||||
export default {
|
||||
name: 'WidgetsAdminEditBasics',
|
||||
components: {
|
||||
FormInput,
|
||||
},
|
||||
props: {
|
||||
original: Object,
|
||||
modelValue: Object,
|
||||
},
|
||||
emits: [
|
||||
"update:modelValue"
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
img() {
|
||||
if (this.modelValue.setup?.icon)
|
||||
return this.modelValue.setup.icon;
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'skin/images/fh_technikum_wien_illustration_klein.png';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="widgets-admin-edit-basics border-bottom mb-3">
|
||||
<div class="d-flex gap-3 my-2">
|
||||
<div class="col-auto">
|
||||
<img
|
||||
:src="img"
|
||||
class="object-fit-contain"
|
||||
style="height: calc(3em + 1.75rem + var(--bs-border-width) * 2 + 2 * var(--bs-body-font-size) * var(--bs-body-line-height)); width: calc(3em + 1.75rem + var(--bs-border-width) * 2 + 2 * var(--bs-body-font-size) * var(--bs-body-line-height))"
|
||||
>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="d-flex gap-3 mb-2">
|
||||
<div class="col">
|
||||
<b>{{ $p.t('mobility/kurzbz') }}: </b>
|
||||
{{ modelValue.widget_kurzbz }}
|
||||
</div>
|
||||
<div v-if="modelValue.widget_id !== undefined" class="col-auto">
|
||||
<b>{{ $p.t('zeitaufzeichnung/id') }}: </b>
|
||||
{{ modelValue.widget_id }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<form-input
|
||||
:label="$p.t('global/beschreibung') + ':'"
|
||||
type="textarea"
|
||||
v-model="modelValue.beschreibung"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { CoreFilterCmpt } from "../../filter/Filter.js";
|
||||
import BsConfirm from "../../Bootstrap/Confirm.js";
|
||||
|
||||
import ApiDashboardWidget from "../../../api/factory/dashboard/widget.js";
|
||||
|
||||
export default {
|
||||
name: 'WidgetsAdminList',
|
||||
components: {
|
||||
CoreFilterCmpt,
|
||||
},
|
||||
props: {
|
||||
unsavedProgress: Boolean,
|
||||
},
|
||||
emit: [
|
||||
"new",
|
||||
"select",
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
tabulatorOptions: {
|
||||
ajaxURL: 'dummy',
|
||||
ajaxRequestFunc: () => this.$api.call(ApiDashboardWidget.listAllOriginal()),
|
||||
ajaxResponse: (url, params, response) => response?.data,
|
||||
columns: [
|
||||
{
|
||||
field: 'setup.icon',
|
||||
title: 'Icon',
|
||||
mutator: value => {
|
||||
if (!value)
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'skin/images/fh_technikum_wien_illustration_klein.png';
|
||||
if (value[0] == '/')
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + value.substr(1);
|
||||
return value;
|
||||
},
|
||||
formatter: 'image',
|
||||
formatterParams: {
|
||||
height: '1.5em',
|
||||
},
|
||||
hozAlign: 'center'
|
||||
},
|
||||
{
|
||||
field: 'setup.name',
|
||||
title: 'Name',
|
||||
},
|
||||
{
|
||||
field: 'widget_kurzbz',
|
||||
title: 'Kurzbz',
|
||||
},
|
||||
{
|
||||
field: 'berechtigung_kurzbz',
|
||||
title: 'Berechtigung',
|
||||
},
|
||||
],
|
||||
locale: true,
|
||||
selectableRows: 1,
|
||||
index: 'widget_id',
|
||||
persistenceID: 'widgets-admin-list',
|
||||
height: '100%',
|
||||
selectableRowsCheck: this.selectableCheck,
|
||||
},
|
||||
tabulatorEvents: [
|
||||
{
|
||||
event: 'rowSelected',
|
||||
handler: this.selectWidget,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
selectableCheck(row) {
|
||||
if (row.isSelected())
|
||||
return false;
|
||||
if (!this.unsavedProgress)
|
||||
return true;
|
||||
|
||||
BsConfirm
|
||||
.popup('selectablecheck' + row.getData().widget_id)
|
||||
.then(() => {
|
||||
const currentRows = row.getTable().getSelectedRows();
|
||||
if (currentRows.length)
|
||||
currentRows[0].deselect();
|
||||
row.select();
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
return false;
|
||||
},
|
||||
newWidget() {
|
||||
if (this.unsavedProgress) {
|
||||
BsConfirm
|
||||
.popup('newcheck')
|
||||
.then(() => this.$emit('new'))
|
||||
.catch(() => {});
|
||||
} else {
|
||||
this.$emit('new');
|
||||
}
|
||||
},
|
||||
selectWidget(data) {
|
||||
this.$emit('select', data.getData());
|
||||
},
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="widgets-admin-list h-100 d-flex flex-column">
|
||||
<core-filter-cmpt
|
||||
ref="table"
|
||||
:tabulator-options="tabulatorOptions"
|
||||
:tabulator-events="tabulatorEvents"
|
||||
:side-menu="false"
|
||||
table-only
|
||||
reload
|
||||
new-btn-show
|
||||
new-btn-label="Widget"
|
||||
@click:new="newWidget"
|
||||
>
|
||||
</core-filter-cmpt>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import BsModal from '../../Bootstrap/Modal.js';
|
||||
import CoreForm from '../../Form/Form.js';
|
||||
import FormInput from '../../Form/Input.js';
|
||||
|
||||
import ApiWidget from '../../../api/factory/dashboard/widget.js';
|
||||
|
||||
export default {
|
||||
name: 'WidgetsAdminNew',
|
||||
components: {
|
||||
BsModal,
|
||||
CoreForm,
|
||||
FormInput,
|
||||
},
|
||||
emit: [
|
||||
"create",
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
generators: [],
|
||||
result: { setup: {} },
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
show() {
|
||||
this.result = {
|
||||
widget_kurzbz: '',
|
||||
setup: {
|
||||
generator: null,
|
||||
},
|
||||
};
|
||||
this.$refs.form.clearValidation();
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
finish() {
|
||||
this.$refs.form
|
||||
.call(ApiWidget.create(this.result))
|
||||
.then(res => {
|
||||
this.$emit('create', { ...this.result, widget_id: res.data });
|
||||
this.$refs.modal.hide();
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$api
|
||||
.call(ApiWidget.generators())
|
||||
.then(res => {
|
||||
this.generators = res.data
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
template: /* html */`
|
||||
<core-form
|
||||
class="widgets-admin-new"
|
||||
ref="form"
|
||||
@submit.prevent="finish"
|
||||
>
|
||||
<bs-modal ref="modal">
|
||||
<template #default>
|
||||
<form-input
|
||||
type="select"
|
||||
:label="'Generator:'"
|
||||
v-model="result.setup.generator"
|
||||
>
|
||||
<option v-for="(generator, name) in generators" :key="name" :value="generator">
|
||||
{{ generator }}
|
||||
</option>
|
||||
</form-input>
|
||||
<form-input
|
||||
type="text"
|
||||
name="widget_kurzbz"
|
||||
:label="$p.t('mobility/kurzbz') + ':'"
|
||||
v-model="result.widget_kurzbz"
|
||||
/>
|
||||
</template>
|
||||
<template #footer>
|
||||
<button type="submit" class="btn btn-primary">OK</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
</template>
|
||||
</bs-modal>
|
||||
</core-form>
|
||||
`
|
||||
}
|
||||
Reference in New Issue
Block a user