diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php
index d52016943..4d3a5f8ee 100644
--- a/application/controllers/api/frontend/v1/stv/Config.php
+++ b/application/controllers/api/frontend/v1/stv/Config.php
@@ -33,6 +33,8 @@ class Config extends FHCAPI_Controller
{
// TODO(chris): permissions
parent::__construct([
+ 'get' => ['admin:r', 'assistenz:r'],
+ 'set' => ['admin:r', 'assistenz:r'],
'student' => ['admin:r', 'assistenz:r'],
'students' => ['admin:r', 'assistenz:r']
]);
@@ -52,6 +54,65 @@ class Config extends FHCAPI_Controller
$this->load->config('stv');
}
+ /**
+ * get App config
+ */
+ public function get()
+ {
+ $this->load->model('system/Variable_model', 'VariableModel');
+ $this->load->config('stv');
+
+ $config = [];
+
+ $result = $this->VariableModel->getVariables(getAuthUID(), ['number_displayed_past_studiensemester']);
+ $data = $this->getDataOrTerminateWithError($result);
+
+ $number_displayed_past_studiensemester_default = $this->config->item('number_displayed_past_studiensemester_default');
+
+ $config['number_displayed_past_studiensemester'] = [
+ "type" => "number",
+ "label" => "Anzahl angezeigter vergangender Studiensemester",// TODO(chris): phrase
+ "value" => $data['number_displayed_past_studiensemester']
+ ?? $number_displayed_past_studiensemester_default
+ ];
+
+ // TODO(chris): Event
+
+ $this->terminateWithSuccess($config);
+ }
+
+ /**
+ * set App config
+ */
+ public function set()
+ {
+ // TODO(chris): rewrite to batch saving
+ $this->load->model('system/Variable_model', 'VariableModel');
+ $this->load->library('form_validation');
+
+ $this->form_validation->set_rules(
+ 'number_displayed_past_studiensemester',
+ "Anzahl angezeigter vergangender Studiensemester",// TODO(chris): phrase
+ 'required|integer'
+ );
+
+ // TODO(chris): Event
+
+ if (!$this->form_validation->run())
+ $this->terminateWithValidationErrors($this->form_validation->error_array());
+
+
+ $this->VariableModel->setVariable(
+ getAuthUID(),
+ 'number_displayed_past_studiensemester',
+ $this->input->post('number_displayed_past_studiensemester')
+ );
+
+ // TODO(chris): Event
+
+ $this->terminateWithSuccess();
+ }
+
public function student()
{
$result = [];
diff --git a/application/controllers/api/frontend/v1/stv/Verband.php b/application/controllers/api/frontend/v1/stv/Verband.php
index 6487b6263..030593293 100644
--- a/application/controllers/api/frontend/v1/stv/Verband.php
+++ b/application/controllers/api/frontend/v1/stv/Verband.php
@@ -188,6 +188,7 @@ class Verband extends FHCAPI_Controller
array_unshift($list, [
'name' => 'PreStudent',
'link' => $link . 'prestudent',
+ 'no_sem_reload' => true,
'stg_kz' => (int)$studiengang_kz,
'children' => $this->getStdSem($link . 'prestudent/', $studiengang_kz)
]);
diff --git a/public/js/api/factory/stv/config.js b/public/js/api/factory/stv/config.js
new file mode 100644
index 000000000..c54b2f8b2
--- /dev/null
+++ b/public/js/api/factory/stv/config.js
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2025 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() {
+ return {
+ method: 'get',
+ url: 'api/frontend/v1/stv/config/get'
+ };
+ },
+ set(params) {
+ return {
+ method: 'post',
+ url: 'api/frontend/v1/stv/config/set',
+ params
+ };
+ }
+};
\ No newline at end of file
diff --git a/public/js/components/Stv/Studentenverwaltung.js b/public/js/components/Stv/Studentenverwaltung.js
index d53d9a789..9db3f9e7b 100644
--- a/public/js/components/Stv/Studentenverwaltung.js
+++ b/public/js/components/Stv/Studentenverwaltung.js
@@ -22,6 +22,7 @@ import StvVerband from "./Studentenverwaltung/Verband.js";
import StvList from "./Studentenverwaltung/List.js";
import StvDetails from "./Studentenverwaltung/Details.js";
import StvStudiensemester from "./Studentenverwaltung/Studiensemester.js";
+import StvConfig from "./Studentenverwaltung/Config.js";
import ApiSearchbar from "../../api/factory/searchbar.js";
import ApiStv from "../../api/factory/stv.js";
@@ -37,7 +38,8 @@ export default {
StvVerband,
StvList,
StvDetails,
- StvStudiensemester
+ StvStudiensemester,
+ StvConfig
},
props: {
defaultSemester: String,
@@ -78,11 +80,13 @@ export default {
},
configShowAufnahmegruppen: this.config.showAufnahmegruppen,
configAllowUebernahmePunkte: this.config.allowUebernahmePunkte,
- configUseReihungstestPunkte: this.config.useReihungstestPunkte
+ configUseReihungstestPunkte: this.config.useReihungstestPunkte,
+ appConfig: Vue.computed(() => this.appconfig)
}
},
data() {
return {
+ appconfig: {},
selected: [],
searchbaroptions: {
origin: 'stv',
@@ -380,6 +384,17 @@ export default {
class="dropdown-menu dropdown-menu-dark dropdown-menu-end rounded-0 text-center m-0"
aria-labelledby="nav-user-btn"
>
+
+
+
+
+
`
};
diff --git a/public/js/components/Stv/Studentenverwaltung/Config.js b/public/js/components/Stv/Studentenverwaltung/Config.js
new file mode 100644
index 000000000..f7a6363cd
--- /dev/null
+++ b/public/js/components/Stv/Studentenverwaltung/Config.js
@@ -0,0 +1,96 @@
+/**
+ * Copyright (C) 2025 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 .
+ */
+
+import BsModal from "../../Bootstrap/Modal.js";
+import FhcForm from "../../Form/Form.js";
+import FormInput from "../../Form/Input.js";
+
+import ApiStvConfig from '../../../api/factory/stv/config.js';
+
+
+export default {
+ name: 'StvConfig',
+ components: {
+ BsModal,
+ FhcForm,
+ FormInput
+ },
+ emits: [
+ 'update:modelValue'
+ ],
+ props: {
+ modelValue: Object
+ },
+ data() {
+ return {
+ setup: {},
+ tempValues: {}
+ };
+ },
+ methods: {
+ update() {
+ this.$refs.form
+ .call(ApiStvConfig.set(this.tempValues))
+ .then(() => {
+ // TODO(chris): phrase
+ this.$emit('update:modelValue', { ...this.tempValues });
+ this.$refs.modal.hide();
+ this.$fhcAlert.alertSuccess('config updated');
+ })
+ .catch(this.$fhcAlert.handleSystemErrors);
+ }
+ },
+ created() {
+ this.$api
+ .call(ApiStvConfig.get())
+ .then(res => {
+ this.setup = {};
+ Object.keys(res.data).forEach(key => {
+ const conf = { ...res.data[key] };
+ this.tempValues[key] = conf.value;
+ delete conf.value;
+ this.setup[key] = conf;
+ });
+ this.$emit('update:modelValue', { ...this.tempValues });
+ })
+ .catch(this.$fhcAlert.handleSystemErrors);
+ },
+ template: /* html */`
+
+
+ {{ $p.t('ui/settings') }}
+
+
+
+
+
+
+
+ `
+};
diff --git a/public/js/components/Stv/Studentenverwaltung/Verband.js b/public/js/components/Stv/Studentenverwaltung/Verband.js
index 072e0e952..4ebc7866a 100644
--- a/public/js/components/Stv/Studentenverwaltung/Verband.js
+++ b/public/js/components/Stv/Studentenverwaltung/Verband.js
@@ -5,6 +5,9 @@ export default {
PvTreetable: primevue.treetable,
PvColumn: primevue.column
},
+ inject: [
+ 'appConfig'
+ ],
emits: [
'selectVerband'
],
@@ -34,6 +37,9 @@ export default {
return this.nodes.filter(node => this.favorites.list.includes(node.key));
return this.nodes;
+ },
+ noSemReloadNodes() {
+ return this.nodes.reduce(this.mapNodesToNoSemReloadNodes, []);
}
},
watch: {
@@ -41,6 +47,14 @@ export default {
if (newVal !== oldVal) {
this.setPreselection();
}
+ },
+ 'appConfig.number_displayed_past_studiensemester'(newVal, oldVal) {
+ if (oldVal !== undefined) {
+ this.noSemReloadNodes.forEach(node => {
+ delete node.children;
+ this.onExpandTreeNode(node);
+ });
+ }
}
},
methods: {
@@ -98,6 +112,13 @@ export default {
if (node.data.link)
this.$emit('selectVerband', {link: node.data.link, studiengang_kz: node.data.stg_kz});
},
+ mapNodesToNoSemReloadNodes(result, node) {
+ if (node.data.no_sem_reload)
+ result.push(node);
+ if (node.children)
+ result = node.children.reduce(this.mapNodesToNoSemReloadNodes, result);
+ return result;
+ },
mapResultToTreeData(el) {
const cp = {
key: ("" + el.link).replace('/', '-'),
diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php
index 97b62a0d9..8f6421a39 100644
--- a/system/phrasesupdate.php
+++ b/system/phrasesupdate.php
@@ -1795,6 +1795,26 @@ $phrases = array(
)
)
),
+ array(
+ 'app' => 'core',
+ 'category' => 'ui',
+ 'phrase' => 'settings',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'Einstellungen',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'Settings',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
array(
'app' => 'core',
'category' => 'ui',