Compare commits

...

3 Commits

Author SHA1 Message Date
0fd2dc3ddb Create management portal in Flutter #39
Some checks are pending
BlockStorage/repertory/pipeline/head Build queued...
2025-03-14 14:54:40 -05:00
d920a55fc0 Create management portal in Flutter #39 2025-03-14 14:47:23 -05:00
edd27e3e34 Create management portal in Flutter #39 2025-03-14 14:33:55 -05:00
3 changed files with 105 additions and 5 deletions

View File

@ -79,6 +79,8 @@ String getBaseUri() {
List<Validator> getSettingValidators(String settingPath) { List<Validator> getSettingValidators(String settingPath) {
switch (settingPath) { switch (settingPath) {
case 'ApiAuth':
return [(value) => value.isNotEmpty];
case 'EncryptConfig.EncryptionToken': case 'EncryptConfig.EncryptionToken':
return [(value) => value.isNotEmpty]; return [(value) => value.isNotEmpty];
case 'EncryptConfig.Path': case 'EncryptConfig.Path':
@ -108,11 +110,11 @@ List<Validator> getSettingValidators(String settingPath) {
case 'HostConfig.Protocol': case 'HostConfig.Protocol':
return [(value) => value == "http" || value == "https"]; return [(value) => value == "http" || value == "https"];
case 'S3Config.AccessKey': case 'S3Config.AccessKey':
return [(value) => value.isNotEmpty]; return [(value) => value.trim().isNotEmpty];
case 'S3Config.Bucket': case 'S3Config.Bucket':
return [(value) => value.trim().isNotEmpty]; return [(value) => value.trim().isNotEmpty];
case 'S3Config.SecretKey': case 'S3Config.SecretKey':
return [(value) => value.isNotEmpty]; return [(value) => value.trim().isNotEmpty];
case 'S3Config.URL': case 'S3Config.URL':
return [(value) => Uri.tryParse(value) != null]; return [(value) => Uri.tryParse(value) != null];
case 'SiaConfig.Bucket': case 'SiaConfig.Bucket':

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:repertory/constants.dart'; import 'package:repertory/constants.dart';
import 'package:repertory/helpers.dart'; import 'package:repertory/helpers.dart';
@ -98,6 +99,9 @@ class _AddMountScreenState extends State<AddMountScreen> {
autofocus: true, autofocus: true,
controller: _mountNameController, controller: _mountNameController,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
inputFormatters: [
FilteringTextInputFormatter.deny(RegExp(r'\s')),
],
onChanged: (_) => _handleChange(_mountType), onChanged: (_) => _handleChange(_mountType),
), ),
], ],

View File

@ -26,6 +26,8 @@ class MountSettingsWidget extends StatefulWidget {
} }
class _MountSettingsWidgetState extends State<MountSettingsWidget> { class _MountSettingsWidgetState extends State<MountSettingsWidget> {
static const _padding = 15.0;
void _addBooleanSetting(list, root, key, value, isAdvanced) { void _addBooleanSetting(list, root, key, value, isAdvanced) {
if (!isAdvanced || widget.showAdvanced) { if (!isAdvanced || widget.showAdvanced) {
list.add( list.add(
@ -181,13 +183,87 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
} }
} }
void _addPasswordSetting(list, root, key, value, isAdvanced) { void _addPasswordSetting(
list,
root,
key,
value,
isAdvanced, {
List<Validator> validators = const [],
}) {
if (!isAdvanced || widget.showAdvanced) { if (!isAdvanced || widget.showAdvanced) {
list.add( list.add(
SettingsTile.navigation( SettingsTile.navigation(
leading: Icon(Icons.password), leading: Icon(Icons.password),
title: Text(key), title: Text(key),
value: Text('*' * (value as String).length), value: Text('*' * (value as String).length),
onPressed: (_) {
String updatedValue1 = value;
String updatedValue2 = value;
showDialog(
context: context,
builder: (context) {
return AlertDialog(
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child: Text('OK'),
onPressed: () {
if (updatedValue1 != updatedValue2) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("'$key' does not match")),
);
return;
}
final result = validators.firstWhereOrNull(
(validator) => !validator(updatedValue1),
);
if (result != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("'$key' is not valid")),
);
return;
}
setState(() {
root[key] = updatedValue1;
widget.onChanged?.call(widget.settings);
});
Navigator.of(context).pop();
},
),
],
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
TextField(
autofocus: true,
controller: TextEditingController(text: updatedValue1),
obscureText: true,
obscuringCharacter: '*',
onChanged: (value) => updatedValue1 = value,
),
const SizedBox(height: _padding),
TextField(
autofocus: false,
controller: TextEditingController(text: updatedValue2),
obscureText: true,
obscuringCharacter: '*',
onChanged: (value) => updatedValue2 = value,
),
],
),
title: Text(key),
);
},
);
},
), ),
); );
} }
@ -242,6 +318,9 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
content: TextField( content: TextField(
autofocus: true, autofocus: true,
controller: TextEditingController(text: updatedValue), controller: TextEditingController(text: updatedValue),
inputFormatters: [
FilteringTextInputFormatter.deny(RegExp(r'\s')),
],
onChanged: (value) => updatedValue = value, onChanged: (value) => updatedValue = value,
), ),
title: Text(key), title: Text(key),
@ -266,7 +345,14 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
widget.settings.forEach((key, value) { widget.settings.forEach((key, value) {
if (key == 'ApiAuth') { if (key == 'ApiAuth') {
_addPasswordSetting(commonSettings, widget.settings, key, value, true); _addPasswordSetting(
commonSettings,
widget.settings,
key,
value,
true,
validators: getSettingValidators(key),
);
} else if (key == 'ApiPort') { } else if (key == 'ApiPort') {
_addIntSetting( _addIntSetting(
commonSettings, commonSettings,
@ -396,6 +482,7 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subKey, subKey,
subValue, subValue,
false, false,
validators: getSettingValidators('$key.$subKey'),
); );
} else if (subKey == 'Path') { } else if (subKey == 'Path') {
_addStringSetting( _addStringSetting(
@ -428,6 +515,7 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subKey, subKey,
subValue, subValue,
false, false,
validators: getSettingValidators('$key.$subKey'),
); );
} else if (subKey == 'ApiPort') { } else if (subKey == 'ApiPort') {
_addIntSetting( _addIntSetting(
@ -506,6 +594,7 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subKey, subKey,
subValue, subValue,
false, false,
validators: getSettingValidators('$key.$subKey'),
); );
} else if (subKey == 'HostNameOrIp') { } else if (subKey == 'HostNameOrIp') {
_addStringSetting( _addStringSetting(
@ -583,18 +672,21 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subKey, subKey,
subValue, subValue,
false, false,
validators: getSettingValidators('$key.$subKey'),
); );
} }
}); });
} else if (key == 'S3Config') { } else if (key == 'S3Config') {
value.forEach((subKey, subValue) { value.forEach((subKey, subValue) {
if (subKey == 'AccessKey') { if (subKey == 'AccessKey') {
_addPasswordSetting( _addStringSetting(
s3ConfigSettings, s3ConfigSettings,
widget.settings[key], widget.settings[key],
subKey, subKey,
subValue, subValue,
Icons.key,
false, false,
validators: getSettingValidators('$key.$subKey'),
); );
} else if (subKey == 'Bucket') { } else if (subKey == 'Bucket') {
_addStringSetting( _addStringSetting(
@ -613,6 +705,7 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subKey, subKey,
subValue, subValue,
false, false,
validators: getSettingValidators('$key.$subKey'),
); );
} else if (subKey == 'Region') { } else if (subKey == 'Region') {
_addStringSetting( _addStringSetting(
@ -631,6 +724,7 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subKey, subKey,
subValue, subValue,
false, false,
validators: getSettingValidators('$key.$subKey'),
); );
} else if (subKey == 'TimeoutMs') { } else if (subKey == 'TimeoutMs') {
_addIntSetting( _addIntSetting(