Skip to content

Commit a3c0338

Browse files
committed
Add configuration panel options configurable by admins.
- Introduced configuration panel options in the Workflow model and updated the Config model to handle these options. - Added migration to include new columns for configuration panel JSON and options in the workflow table. - Created UploadWorkflowConfigurationOptions component to manage configuration panel options in the Admin Settings. - Enhanced VideoUpload component to filter and display configuration panel options based on admin settings. - Updated I18NText component to support text input for configuration labels.
1 parent a47cda1 commit a3c0338

File tree

7 files changed

+328
-32
lines changed

7 files changed

+328
-32
lines changed

lib/Models/Config.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,20 @@ public function updateSettings($json)
152152
}
153153
Workflow::updateSettings($this->id, $workflow_settings);
154154

155+
// Update configration panel options.
156+
$configuration_panel_options = [];
157+
if (isset($json['settings']['configuration_panel_options'])) {
158+
foreach ($json['settings']['configuration_panel_options'] as $config_panel_options) {
159+
$workflow_id = $config_panel_options['id'];
160+
unset($config_panel_options['id']);
161+
if (!empty($config_panel_options)) {
162+
$configuration_panel_options[$workflow_id] = $config_panel_options;
163+
}
164+
}
165+
unset($json['settings']['configuration_panel_options']);
166+
}
167+
Workflow::updateConfigPanelOptions($this->id, $configuration_panel_options);
168+
155169
$this->setData($json);
156170
return $this->store();
157171
}

lib/Models/Workflow.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,12 @@ public static function updateWorkflowsByConfigId($config_id)
6464
$entry->setValue('displayname', $wf_def['title']);
6565
// In case WF is already there, we also update the config panel json.
6666
$entry->setValue('configuration_panel_json', $wf_config_panel_filtered);
67+
6768
$entry->store();
6869

70+
// Take care of config panel options.
71+
self::configPanelOptionsMapper($entry);
72+
6973
$found = true;
7074
unset($db_workflows[$key]);
7175
break;
@@ -86,6 +90,8 @@ public static function updateWorkflowsByConfigId($config_id)
8690
$new_entry->setValue('settings', []);
8791

8892
$new_entry->store();
93+
94+
self::configPanelOptionsMapper($new_entry);
8995
}
9096
}
9197
} catch (\Throwable $th) {
@@ -144,8 +150,67 @@ public function toArray($only_these_fields = null)
144150

145151
// We then convert the config panel json string to array.
146152
$config_panel_json_string = !empty($ret['configuration_panel_json']) ? $ret['configuration_panel_json'] : '[]';
153+
$configuration_panel_options = !empty($ret['configuration_panel_options']) ? $ret['configuration_panel_options'] : '[]';
147154
$ret['configuration_panel_json'] = json_decode($config_panel_json_string, true) ?? [];
155+
$ret['configuration_panel_options'] = json_decode($configuration_panel_options, true) ?? [];
148156

149157
return $ret;
150158
}
159+
160+
private static function configPanelOptionsMapper($entry)
161+
{
162+
$existing_options = json_decode($entry->configuration_panel_options, true) ?? [];
163+
$config_panel = json_decode($entry->configuration_panel_json, true) ?? [];
164+
$eligible_fieldset = [];
165+
166+
if (!empty($config_panel)) {
167+
foreach ($config_panel as $item) {
168+
$description = $item['description'] ?? '';
169+
if (!empty($item['fieldset'])) {
170+
foreach ($item['fieldset'] as $cp_item) {
171+
$name = $cp_item['name'];
172+
$eligible_fieldset[] = $name;
173+
$label = $cp_item['label'] ?? $description;
174+
$show = true;
175+
if (!isset($existing_options[$name])) {
176+
$existing_options[$name] = [
177+
'displayName' => [
178+
'default' => $label,
179+
],
180+
'show' => $show
181+
];
182+
}
183+
}
184+
}
185+
}
186+
}
187+
188+
$to_remove_options = array_diff_key($existing_options, array_flip($eligible_fieldset));
189+
foreach ($to_remove_options as $key => $option) {
190+
unset($existing_options[$key]);
191+
}
192+
193+
$entry->setValue('configuration_panel_options', json_encode($existing_options));
194+
$entry->store();
195+
}
196+
197+
/**
198+
* Update configuration panel options of workflows
199+
*
200+
* @param string $config_id related config to ensure correct oc service
201+
* @param array $config_panel_options Array of configuration panel options to update
202+
* @return void
203+
*/
204+
public static function updateConfigPanelOptions($config_id, $config_panel_options)
205+
{
206+
foreach ($config_panel_options as $wf_id => $config_panel_options) {
207+
// Ensure same config is modified
208+
$workflow = self::findOneBySQL('id = ? AND config_id = ?', [$wf_id, $config_id]);
209+
210+
if (!empty($workflow)) {
211+
$workflow->configuration_panel_options = json_encode($config_panel_options);
212+
$workflow->store();
213+
}
214+
}
215+
}
151216
}

migrations/115_add_workflow_configuration_panel_json.php renamed to migrations/116_add_workflow_configuration_panel_json.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ class AddWorkflowConfigurationPanelJson extends Migration
66
{
77
public function description()
88
{
9-
return 'Add configuration panel (JSON) column to table workflow';
9+
return 'Add configuration panel (JSON) and options columns to table workflow';
1010
}
1111

1212
public function up()
1313
{
1414
$db = DBManager::get();
1515

1616
$db->exec("ALTER TABLE `oc_workflow`
17-
ADD COLUMN `configuration_panel_json` TEXT NULL
17+
ADD COLUMN `configuration_panel_json` TEXT NULL,
18+
ADD COLUMN `configuration_panel_options` TEXT NULL
1819
");
1920

2021
SimpleOrMap::expireTableScheme();
@@ -24,7 +25,10 @@ public function down()
2425
{
2526
$db = DBManager::get();
2627

27-
$db->exec("ALTER TABLE `oc_workflow` DROP COLUMN `configuration_panel_json`");
28+
$db->exec("ALTER TABLE `oc_workflow`
29+
DROP COLUMN `configuration_panel_json`,
30+
DROP COLUMN `configuration_panel_options`
31+
");
2832

2933
SimpleOrMap::expireTableScheme();
3034
}

vueapp/components/Config/EditServer.vue

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828

2929
<WorkflowOptions :disabled="currentId === 'new'" ref="workflow-form"/>
3030

31+
<UploadWorkflowConfigurationOptions :disabled="currentId === 'new'" ref="upload-workflow-form"/>
32+
3133
<UploadOptions :configId="currentId" :disabled="currentId === 'new'"/>
3234
</form>
3335

@@ -58,6 +60,7 @@ import MessageList from "@/components/MessageList";
5860
import ConfigOption from "@/components/Config/ConfigOption";
5961
import WorkflowOptions from "@/components/Config/WorkflowOptions";
6062
import UploadOptions from "@/components/Config/UploadOptions";
63+
import UploadWorkflowConfigurationOptions from "@/components/Config/UploadWorkflowConfigurationOptions";
6164
6265
import axios from "@/common/axios.service";
6366
@@ -72,6 +75,7 @@ export default {
7275
MessageList,
7376
WorkflowOptions,
7477
UploadOptions,
78+
UploadWorkflowConfigurationOptions,
7579
},
7680
7781
props: {
@@ -143,6 +147,22 @@ export default {
143147
placeholder: 'CONSUMERSECRET',
144148
required: true
145149
},
150+
{
151+
description: this.$gettext('Timeout (in Millisekunden)'),
152+
name: 'timeout_ms',
153+
value: this.currentConfig.timeout_ms,
154+
type: 'integer',
155+
placeholder: '0',
156+
required: true
157+
},
158+
{
159+
description: this.$gettext('Verbindungs-Timeout (in Millisekunden)'),
160+
name: 'connect_timeout_ms',
161+
value: this.currentConfig.connect_timeout_ms,
162+
type: 'integer',
163+
placeholder: '2000',
164+
required: true
165+
},
146166
{
147167
description: this.$gettext('Zeitpuffer (in Sekunden) um Überlappungen zu verhindern'),
148168
name: 'time_buffer_overlap',
@@ -178,22 +198,6 @@ export default {
178198
type: 'boolean',
179199
required: false
180200
},
181-
{
182-
description: this.$gettext('Timeout (in Millisekunden)'),
183-
name: 'timeout_ms',
184-
value: this.currentConfig.timeout_ms,
185-
type: 'integer',
186-
placeholder: '0',
187-
required: true
188-
},
189-
{
190-
description: this.$gettext('Verbindungs-Timeout (in Millisekunden)'),
191-
name: 'connect_timeout_ms',
192-
value: this.currentConfig.connect_timeout_ms,
193-
type: 'integer',
194-
placeholder: '2000',
195-
required: true
196-
}
197201
];
198202
},
199203
@@ -229,9 +233,12 @@ export default {
229233
this.currentConfig.workflow_configs = this.simple_config_list.workflow_configs;
230234
}
231235
232-
// Add workflow settings
233236
if (this.simple_config_list?.workflows) {
237+
// Add workflow settings
234238
let workflow_settings = [];
239+
240+
// Add workflow configuration panel options.
241+
let configuration_panel_options = [];
235242
for (let workflow of this.simple_config_list?.workflows) {
236243
// Check if upload file type is set
237244
if (!Array.isArray(workflow.settings)) {
@@ -246,8 +253,16 @@ export default {
246253
'id': workflow.id,
247254
...workflow.settings,
248255
});
256+
257+
if (workflow?.configuration_panel_options) {
258+
configuration_panel_options.push({
259+
'id': workflow.id,
260+
...workflow.configuration_panel_options,
261+
});
262+
}
249263
}
250264
this.currentConfig.workflow_settings = workflow_settings;
265+
this.currentConfig.configuration_panel_options = configuration_panel_options;
251266
}
252267
253268
this.$store.dispatch('configUpdate', this.currentConfig)
@@ -310,9 +325,11 @@ export default {
310325
let view = this;
311326
// We need to wait for a short time so the component is actually visible
312327
setTimeout(() => {
313-
view.$refs['workflow-form'].$el.scrollIntoView({
314-
behavior: 'smooth'
315-
});
328+
if (view?.$refs?.['workflow-form']?.$el) {
329+
view.$refs['workflow-form'].$el.scrollIntoView({
330+
behavior: 'smooth'
331+
});
332+
}
316333
}, 10);
317334
}
318335

vueapp/components/Config/I18NText.vue

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,16 @@
99
}"
1010
:data-lang="lang.id"
1111
:data-icon="`url(` + getLangImage(lang) + `)`">
12+
<input
13+
v-if="type === 'text'"
14+
type="text"
15+
ref="`studip_i18n_text_` + lang.id"
16+
:name="`studip_i18n_text_` + uuid + '_' + lang.id"
17+
v-model="currentInputValue"
18+
@keyup="updateInputValue"
19+
>
1220
<textarea
21+
v-else-if="type === 'textarea'"
1322
:value="currentText[lang.id]"
1423
:id="`studip_wysiwyg_` + uuid + '_' + lang.id"
1524
:ref="`studip_wysiwyg_` + lang.id"
@@ -21,14 +30,14 @@
2130
<select tabindex="-1" class="i18n"
2231
:style="`background-image: url(` + getLangImage(selectedLang) + `)`"
2332
v-model="selectedLang"
24-
@change="initCKE()"
33+
@change="LanguageChange"
2534
>
2635
<option
2736
v-for="lang in languages"
2837
:value="lang"
2938
:style="`background-image: url(` + getLangImage(lang) + `)`"
3039
>
31-
{{ lang.name}}
40+
{{ lang.name }}
3241
</option>
3342
</select>
3443
</div>
@@ -48,18 +57,29 @@ export default {
4857
},
4958
languages: {
5059
type: Object
60+
},
61+
type: {
62+
type: String,
63+
required: false,
64+
default: "textarea"
65+
},
66+
callbackKey: {
67+
type: String,
68+
default: null
5169
}
5270
},
5371
5472
emits: ['updateValue'],
5573
5674
data() {
5775
return {
76+
currentInputValue: null,
5877
currentText: null,
5978
selectedLang: null,
6079
fallbackActive: false,
6180
wysiwyg_editor: {},
62-
uuid: Math.random().toString(16).slice(2)
81+
uuid: Math.random().toString(16).slice(2),
82+
debounceTimeout: null,
6383
}
6484
},
6585
@@ -69,6 +89,9 @@ export default {
6989
7090
beforeMount() {
7191
this.selectedLang = this.languages[Object.keys(this.languages)[0]];
92+
if (Object.keys(this.languages).includes('default')) {
93+
this.selectedLang = this.languages.default;
94+
}
7295
let json;
7396
try {
7497
json = JSON.parse(this.text);
@@ -77,10 +100,20 @@ export default {
77100
}
78101
79102
this.currentText = json;
103+
this.currentInputValue = this.text[this.selectedLang.id];
104+
},
105+
106+
beforeUnmount() {
107+
if (this.debounceTimeout !== null) {
108+
clearTimeout(this.debounceTimeout);
109+
}
80110
},
81111
82112
methods: {
83113
getLangImage(lang) {
114+
if (lang.id == 'default') {
115+
return `${STUDIP.ASSETS_URL}images/${lang.picture}`;
116+
}
84117
return OpencastPlugin.ASSETS_URL + 'images/languages/' + lang.picture;
85118
},
86119
@@ -89,6 +122,10 @@ export default {
89122
return false;
90123
}
91124
125+
if (this.type !== 'textarea') {
126+
return false;
127+
}
128+
92129
let textarea = this.$refs['studip_wysiwyg_' + this.selectedLang.id][0];
93130
94131
if (!this.wysiwyg_editor[this.selectedLang.id]) {
@@ -131,6 +168,23 @@ export default {
131168
}
132169
133170
this.$emit('updateValue', JSON.stringify(this.currentText));
171+
},
172+
173+
LanguageChange() {
174+
if (this.type == 'textarea') {
175+
this.initCKE();
176+
return;
177+
}
178+
this.currentInputValue = this.text?.[this.selectedLang.id] ?? null;
179+
},
180+
181+
updateInputValue() {
182+
if (this.debounceTimeout !== null) {
183+
clearTimeout(this.debounceTimeout);
184+
}
185+
this.debounceTimeout = setTimeout(() => {
186+
this.$emit('updateValue', this.currentInputValue, this.selectedLang.id, this.callbackKey);
187+
}, 500);
134188
}
135189
}
136190
}

0 commit comments

Comments
 (0)