Create management portal in Flutter #39

This commit is contained in:
Scott E. Graves 2025-03-05 09:34:57 -06:00
parent a0bf5ec3d2
commit 51ee46e279
8 changed files with 165 additions and 84 deletions

View File

@ -1 +1 @@
const String appTitle = "Repertory Management Portal"; const String appTitle = 'Repertory Management Portal';

View File

@ -1,15 +1,15 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
String formatMountName(String type, String name) { String formatMountName(String type, String name) {
if (type == "remote") { if (type == 'remote') {
return name.replaceAll("_", ":"); return name.replaceAll('_', ':');
} }
return name; return name;
} }
String getBaseUri() { String getBaseUri() {
if (kDebugMode) { if (kDebugMode) {
return "http://127.0.0.1:30000"; return 'http://127.0.0.1:30000';
} }
return Uri.base.origin; return Uri.base.origin;
} }

View File

@ -77,16 +77,22 @@ class MyHomePage extends StatefulWidget {
class _MyHomePageState extends State<MyHomePage> { class _MyHomePageState extends State<MyHomePage> {
bool _allowAdd = true; bool _allowAdd = true;
String? _apiAuth; String? _apiAuth;
String? _apiPort;
String? _bucket; String? _bucket;
String _mountType = "Encrypt"; String? _encryptionToken;
String _mountName = ""; String? _hostNameOrIp;
String _mountType = 'Encrypt';
String _mountName = '';
String? _path; String? _path;
void _resetData() { void _resetData() {
_apiAuth = null; _apiAuth = null;
_apiPort = null;
_bucket = null; _bucket = null;
_mountType = "Encrypt"; _encryptionToken = null;
_mountName = ""; _hostNameOrIp = null;
_mountName = '';
_mountType = 'Encrypt';
_path = null; _path = null;
} }
@ -113,12 +119,19 @@ class _MyHomePageState extends State<MyHomePage> {
return AddMountWidget( return AddMountWidget(
mountType: _mountType, mountType: _mountType,
onApiAuthChanged: (apiAuth) => _apiAuth = apiAuth, onApiAuthChanged: (apiAuth) => _apiAuth = apiAuth,
onApiPortChanged: (apiPort) => _apiPort = apiPort,
onBucketChanged: (bucket) => _bucket = bucket, onBucketChanged: (bucket) => _bucket = bucket,
onEncryptionTokenChanged:
(encryptionToken) =>
_encryptionToken = encryptionToken,
onHostNameOrIpChanged:
(hostNameOrIp) =>
_hostNameOrIp = hostNameOrIp,
onNameChanged: onNameChanged:
(mountName) => _mountName = mountName ?? "", (mountName) => _mountName = mountName ?? '',
onPathChanged: (path) => _path = path, onPathChanged: (path) => _path = path,
onTypeChanged: onTypeChanged:
(mountType) => _mountType = mountType ?? "S3", (mountType) => _mountType = mountType ?? 'S3',
); );
}, },
), ),
@ -140,7 +153,10 @@ class _MyHomePageState extends State<MyHomePage> {
_mountType, _mountType,
_mountName, _mountName,
apiAuth: _apiAuth, apiAuth: _apiAuth,
apiPort: _apiPort,
bucket: _bucket, bucket: _bucket,
encryptionToken: _encryptionToken,
hostNameOrIp: _hostNameOrIp,
path: _path, path: _path,
) )
.then((_) { .then((_) {

View File

@ -79,6 +79,18 @@ class Mount with ChangeNotifier {
} }
Future<String?> getMountLocation() async { Future<String?> getMountLocation() async {
return "~/mnt/encrypt"; final response = await http.get(
Uri.parse(
Uri.encodeFull(
'${getBaseUri()}/api/v1/get_mount_location?name=$name&type=$type',
),
),
);
if (response.statusCode != 200) {
return null;
}
return jsonDecode(response.body)['Location'] as String;
} }
} }

View File

@ -52,13 +52,18 @@ class MountList with ChangeNotifier {
String type, String type,
String name, { String name, {
String? apiAuth, String? apiAuth,
String? apiPort,
String? bucket, String? bucket,
String? encryptionToken,
String? hostNameOrIp,
String? path, String? path,
}) async { }) async {
await http.post( await http.post(
Uri.parse( Uri.parse(
Uri.encodeFull( Uri.encodeFull(
'${getBaseUri()}/api/v1/add_mount?name=$name&type=$type&bucket=$bucket&path=$path&apiAuth=$apiAuth', '${getBaseUri()}/api/v1/add_mount?name=$name&type=$type&bucket=$bucket'
'&path=$path&apiAuth=$apiAuth&apiPort=$apiPort&hostNameOrIp=$hostNameOrIp'
'&encryptionToken=$encryptionToken',
), ),
), ),
); );

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
class MountConfig { class MountConfig {
final String _name; final String _name;
String _path = ""; String _path = '';
Map<String, dynamic> _settings = {}; Map<String, dynamic> _settings = {};
IconData _state = Icons.toggle_off; IconData _state = Icons.toggle_off;
final String _type; final String _type;
@ -25,7 +25,7 @@ class MountConfig {
} }
void updateStatus(Map<String, dynamic> status) { void updateStatus(Map<String, dynamic> status) {
_path = status["Location"] as String; _path = status['Location'] as String;
_state = status["Active"] as bool ? Icons.toggle_on : Icons.toggle_off; _state = status['Active'] as bool ? Icons.toggle_on : Icons.toggle_off;
} }
} }

View File

@ -3,7 +3,10 @@ import 'package:flutter/material.dart';
class AddMountWidget extends StatefulWidget { class AddMountWidget extends StatefulWidget {
final String mountType; final String mountType;
final void Function(String? newApiAuth) onApiAuthChanged; final void Function(String? newApiAuth) onApiAuthChanged;
final void Function(String? newApiPort) onApiPortChanged;
final void Function(String? newBucket) onBucketChanged; final void Function(String? newBucket) onBucketChanged;
final void Function(String? newEncryptionToken) onEncryptionTokenChanged;
final void Function(String? newHostNameOrIp) onHostNameOrIpChanged;
final void Function(String? newName) onNameChanged; final void Function(String? newName) onNameChanged;
final void Function(String? newPath) onPathChanged; final void Function(String? newPath) onPathChanged;
final void Function(String? newType) onTypeChanged; final void Function(String? newType) onTypeChanged;
@ -12,7 +15,10 @@ class AddMountWidget extends StatefulWidget {
super.key, super.key,
required this.mountType, required this.mountType,
required this.onApiAuthChanged, required this.onApiAuthChanged,
required this.onApiPortChanged,
required this.onBucketChanged, required this.onBucketChanged,
required this.onEncryptionTokenChanged,
required this.onHostNameOrIpChanged,
required this.onNameChanged, required this.onNameChanged,
required this.onPathChanged, required this.onPathChanged,
required this.onTypeChanged, required this.onTypeChanged,
@ -23,7 +29,7 @@ class AddMountWidget extends StatefulWidget {
} }
class _AddMountWidgetState extends State<AddMountWidget> { class _AddMountWidgetState extends State<AddMountWidget> {
static const _items = <String>["Encrypt", "S3", "Sia"]; static const _items = <String>['Encrypt', 'Remote', 'S3', 'Sia'];
String? _mountType; String? _mountType;
@ -114,7 +120,7 @@ class _AddMountWidgetState extends State<AddMountWidget> {
decoration: InputDecoration(), decoration: InputDecoration(),
onChanged: widget.onApiAuthChanged, onChanged: widget.onApiAuthChanged,
), ),
if (mountTypeLower == 'sia' || mountTypeLower == 's3') if (mountTypeLower == 's3' || mountTypeLower == 'sia')
Text( Text(
'Bucket', 'Bucket',
textAlign: TextAlign.left, textAlign: TextAlign.left,
@ -123,11 +129,53 @@ class _AddMountWidgetState extends State<AddMountWidget> {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
if (mountTypeLower == 'sia' || mountTypeLower == 's3') if (mountTypeLower == 's3' || mountTypeLower == 'sia')
TextField( TextField(
decoration: InputDecoration(), decoration: InputDecoration(),
onChanged: widget.onBucketChanged, onChanged: widget.onBucketChanged,
), ),
if (mountTypeLower == 'remote')
Text(
'HostNameOrIp',
textAlign: TextAlign.left,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
),
if (mountTypeLower == 'remote')
TextField(
decoration: InputDecoration(),
onChanged: widget.onHostNameOrIpChanged,
),
if (mountTypeLower == 'remote')
Text(
'ApiPort',
textAlign: TextAlign.left,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
),
if (mountTypeLower == 'remote')
TextField(
decoration: InputDecoration(),
onChanged: widget.onApiPortChanged,
),
if (mountTypeLower == 'remote')
Text(
'EncryptionToken',
textAlign: TextAlign.left,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
),
if (mountTypeLower == 'remote')
TextField(
decoration: InputDecoration(),
onChanged: widget.onEncryptionTokenChanged,
),
], ],
); );
} }

View File

@ -200,70 +200,70 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
List<SettingsTile> siaConfigSettings = []; List<SettingsTile> siaConfigSettings = [];
_settings.forEach((key, value) { _settings.forEach((key, value) {
if (key == "ApiAuth") { if (key == 'ApiAuth') {
_addPasswordSetting(commonSettings, _settings, key, value); _addPasswordSetting(commonSettings, _settings, key, value);
} else if (key == "ApiPort") { } else if (key == 'ApiPort') {
_addIntSetting(commonSettings, _settings, key, value); _addIntSetting(commonSettings, _settings, key, value);
} else if (key == "ApiUser") { } else if (key == 'ApiUser') {
_addStringSetting(commonSettings, _settings, key, value, Icons.person); _addStringSetting(commonSettings, _settings, key, value, Icons.person);
} else if (key == "DatabaseType") { } else if (key == 'DatabaseType') {
_addListSetting(commonSettings, _settings, key, value, [ _addListSetting(commonSettings, _settings, key, value, [
"rocksdb", 'rocksdb',
"sqlite", 'sqlite',
], Icons.dataset); ], Icons.dataset);
} else if (key == "DownloadTimeoutSeconds") { } else if (key == 'DownloadTimeoutSeconds') {
_addIntSetting(commonSettings, _settings, key, value); _addIntSetting(commonSettings, _settings, key, value);
} else if (key == "EnableDownloadTimeout") { } else if (key == 'EnableDownloadTimeout') {
_addBooleanSetting(commonSettings, _settings, key, value); _addBooleanSetting(commonSettings, _settings, key, value);
} else if (key == "EnableDriveEvents") { } else if (key == 'EnableDriveEvents') {
_addBooleanSetting(commonSettings, _settings, key, value); _addBooleanSetting(commonSettings, _settings, key, value);
} else if (key == "EventLevel") { } else if (key == 'EventLevel') {
_addListSetting(commonSettings, _settings, key, value, [ _addListSetting(commonSettings, _settings, key, value, [
"critical", 'critical',
"error", 'error',
"warn", 'warn',
"info", 'info',
"debug", 'debug',
"trace", 'trace',
], Icons.event); ], Icons.event);
} else if (key == "EvictionDelayMinutes") { } else if (key == 'EvictionDelayMinutes') {
_addIntSetting(commonSettings, _settings, key, value); _addIntSetting(commonSettings, _settings, key, value);
} else if (key == "EvictionUseAccessedTime") { } else if (key == 'EvictionUseAccessedTime') {
_addBooleanSetting(commonSettings, _settings, key, value); _addBooleanSetting(commonSettings, _settings, key, value);
} else if (key == "MaxCacheSizeBytes") { } else if (key == 'MaxCacheSizeBytes') {
_addIntSetting(commonSettings, _settings, key, value); _addIntSetting(commonSettings, _settings, key, value);
} else if (key == "MaxUploadCount") { } else if (key == 'MaxUploadCount') {
_addIntSetting(commonSettings, _settings, key, value); _addIntSetting(commonSettings, _settings, key, value);
} else if (key == "OnlineCheckRetrySeconds") { } else if (key == 'OnlineCheckRetrySeconds') {
_addIntSetting(commonSettings, _settings, key, value); _addIntSetting(commonSettings, _settings, key, value);
} else if (key == "PreferredDownloadType") { } else if (key == 'PreferredDownloadType') {
_addListSetting(commonSettings, _settings, key, value, [ _addListSetting(commonSettings, _settings, key, value, [
"default", 'default',
"direct", 'direct',
"ring_buffer", 'ring_buffer',
], Icons.download); ], Icons.download);
} else if (key == "RetryReadCount") { } else if (key == 'RetryReadCount') {
_addIntSetting(commonSettings, _settings, key, value); _addIntSetting(commonSettings, _settings, key, value);
} else if (key == "RingBufferFileSize") { } else if (key == 'RingBufferFileSize') {
_addIntListSetting( _addIntListSetting(
commonSettings, commonSettings,
_settings, _settings,
key, key,
value, value,
["128", "256", "512", "1024", "2048"], ['128', '256', '512', '1024', '2048'],
512, 512,
Icons.animation, Icons.animation,
); );
} else if (key == "EncryptConfig") { } else if (key == 'EncryptConfig') {
value.forEach((subKey, subValue) { value.forEach((subKey, subValue) {
if (subKey == "EncryptionToken") { if (subKey == 'EncryptionToken') {
_addPasswordSetting( _addPasswordSetting(
encryptConfigSettings, encryptConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "Path") { } else if (subKey == 'Path') {
_addStringSetting( _addStringSetting(
encryptConfigSettings, encryptConfigSettings,
_settings[key], _settings[key],
@ -273,9 +273,9 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
); );
} }
}); });
} else if (key == "HostConfig") { } else if (key == 'HostConfig') {
value.forEach((subKey, subValue) { value.forEach((subKey, subValue) {
if (subKey == "AgentString") { if (subKey == 'AgentString') {
_addStringSetting( _addStringSetting(
hostConfigSettings, hostConfigSettings,
_settings[key], _settings[key],
@ -283,21 +283,21 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subValue, subValue,
Icons.support_agent, Icons.support_agent,
); );
} else if (subKey == "ApiPassword") { } else if (subKey == 'ApiPassword') {
_addPasswordSetting( _addPasswordSetting(
hostConfigSettings, hostConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "ApiPort") { } else if (subKey == 'ApiPort') {
_addIntSetting( _addIntSetting(
hostConfigSettings, hostConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "ApiUser") { } else if (subKey == 'ApiUser') {
_addStringSetting( _addStringSetting(
hostConfigSettings, hostConfigSettings,
_settings[key], _settings[key],
@ -305,7 +305,7 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subValue, subValue,
Icons.person, Icons.person,
); );
} else if (subKey == "HostNameOrIp") { } else if (subKey == 'HostNameOrIp') {
_addStringSetting( _addStringSetting(
hostConfigSettings, hostConfigSettings,
_settings[key], _settings[key],
@ -313,7 +313,7 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subValue, subValue,
Icons.computer, Icons.computer,
); );
} else if (subKey == "Path") { } else if (subKey == 'Path') {
_addStringSetting( _addStringSetting(
hostConfigSettings, hostConfigSettings,
_settings[key], _settings[key],
@ -321,16 +321,16 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subValue, subValue,
Icons.route, Icons.route,
); );
} else if (subKey == "Protocol") { } else if (subKey == 'Protocol') {
_addListSetting( _addListSetting(
hostConfigSettings, hostConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
["http", "https"], ['http', 'https'],
Icons.http, Icons.http,
); );
} else if (subKey == "TimeoutMs") { } else if (subKey == 'TimeoutMs') {
_addIntSetting( _addIntSetting(
hostConfigSettings, hostConfigSettings,
_settings[key], _settings[key],
@ -339,23 +339,23 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
); );
} }
}); });
} else if (key == "RemoteConfig") { } else if (key == 'RemoteConfig') {
value.forEach((subKey, subValue) { value.forEach((subKey, subValue) {
if (subKey == "ApiPort") { if (subKey == 'ApiPort') {
_addIntSetting( _addIntSetting(
remoteConfigSettings, remoteConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "EncryptionToken") { } else if (subKey == 'EncryptionToken') {
_addPasswordSetting( _addPasswordSetting(
remoteConfigSettings, remoteConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "HostNameOrIp") { } else if (subKey == 'HostNameOrIp') {
_addStringSetting( _addStringSetting(
remoteConfigSettings, remoteConfigSettings,
_settings[key], _settings[key],
@ -363,21 +363,21 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subValue, subValue,
Icons.computer, Icons.computer,
); );
} else if (subKey == "MaxConnections") { } else if (subKey == 'MaxConnections') {
_addIntSetting( _addIntSetting(
remoteConfigSettings, remoteConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "ReceiveTimeoutMs") { } else if (subKey == 'ReceiveTimeoutMs') {
_addIntSetting( _addIntSetting(
remoteConfigSettings, remoteConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "SendTimeoutMs") { } else if (subKey == 'SendTimeoutMs') {
_addIntSetting( _addIntSetting(
remoteConfigSettings, remoteConfigSettings,
_settings[key], _settings[key],
@ -386,27 +386,27 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
); );
} }
}); });
} else if (key == "RemoteMount") { } else if (key == 'RemoteMount') {
value.forEach((subKey, subValue) { value.forEach((subKey, subValue) {
if (subKey == "Enable") { if (subKey == 'Enable') {
List<SettingsTile> tempSettings = []; List<SettingsTile> tempSettings = [];
_addBooleanSetting(tempSettings, _settings[key], subKey, subValue); _addBooleanSetting(tempSettings, _settings[key], subKey, subValue);
remoteMountSettings.insertAll(0, tempSettings); remoteMountSettings.insertAll(0, tempSettings);
} else if (subKey == "ApiPort") { } else if (subKey == 'ApiPort') {
_addIntSetting( _addIntSetting(
remoteMountSettings, remoteMountSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "ClientPoolSize") { } else if (subKey == 'ClientPoolSize') {
_addIntSetting( _addIntSetting(
remoteMountSettings, remoteMountSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "EncryptionToken") { } else if (subKey == 'EncryptionToken') {
_addPasswordSetting( _addPasswordSetting(
remoteMountSettings, remoteMountSettings,
_settings[key], _settings[key],
@ -415,16 +415,16 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
); );
} }
}); });
} else if (key == "S3Config") { } else if (key == 'S3Config') {
value.forEach((subKey, subValue) { value.forEach((subKey, subValue) {
if (subKey == "AccessKey") { if (subKey == 'AccessKey') {
_addPasswordSetting( _addPasswordSetting(
s3ConfigSettings, s3ConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "Bucket") { } else if (subKey == 'Bucket') {
_addStringSetting( _addStringSetting(
s3ConfigSettings, s3ConfigSettings,
_settings[key], _settings[key],
@ -432,14 +432,14 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subValue, subValue,
Icons.folder, Icons.folder,
); );
} else if (subKey == "EncryptionToken") { } else if (subKey == 'EncryptionToken') {
_addPasswordSetting( _addPasswordSetting(
s3ConfigSettings, s3ConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "Region") { } else if (subKey == 'Region') {
_addStringSetting( _addStringSetting(
s3ConfigSettings, s3ConfigSettings,
_settings[key], _settings[key],
@ -447,16 +447,16 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subValue, subValue,
Icons.map, Icons.map,
); );
} else if (subKey == "SecretKey") { } else if (subKey == 'SecretKey') {
_addPasswordSetting( _addPasswordSetting(
s3ConfigSettings, s3ConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "TimeoutMs") { } else if (subKey == 'TimeoutMs') {
_addIntSetting(s3ConfigSettings, _settings[key], subKey, subValue); _addIntSetting(s3ConfigSettings, _settings[key], subKey, subValue);
} else if (subKey == "URL") { } else if (subKey == 'URL') {
_addStringSetting( _addStringSetting(
s3ConfigSettings, s3ConfigSettings,
_settings[key], _settings[key],
@ -464,14 +464,14 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
subValue, subValue,
Icons.http, Icons.http,
); );
} else if (subKey == "UsePathStyle") { } else if (subKey == 'UsePathStyle') {
_addBooleanSetting( _addBooleanSetting(
s3ConfigSettings, s3ConfigSettings,
_settings[key], _settings[key],
subKey, subKey,
subValue, subValue,
); );
} else if (subKey == "UseRegionInURL") { } else if (subKey == 'UseRegionInURL') {
_addBooleanSetting( _addBooleanSetting(
s3ConfigSettings, s3ConfigSettings,
_settings[key], _settings[key],
@ -480,9 +480,9 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
); );
} }
}); });
} else if (key == "SiaConfig") { } else if (key == 'SiaConfig') {
value.forEach((subKey, subValue) { value.forEach((subKey, subValue) {
if (subKey == "Bucket") { if (subKey == 'Bucket') {
_addStringSetting( _addStringSetting(
siaConfigSettings, siaConfigSettings,
_settings[key], _settings[key],
@ -527,7 +527,7 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
SettingsSection( SettingsSection(
title: const Text('Remote Mount'), title: const Text('Remote Mount'),
tiles: tiles:
_settings["RemoteMount"]["Enable"] as bool _settings['RemoteMount']['Enable'] as bool
? remoteMountSettings ? remoteMountSettings
: [remoteMountSettings[0]], : [remoteMountSettings[0]],
), ),