Compare commits

...

3 Commits

Author SHA1 Message Date
2a1abd0bb0 save ui settings
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-03-16 15:52:46 -05:00
c75ce9ad21 save ui settings 2025-03-16 15:41:50 -05:00
9afc8e3cb6 save ui settings 2025-03-16 15:31:34 -05:00
9 changed files with 87 additions and 17 deletions

View File

@ -71,6 +71,8 @@ private:
void handle_put_set_value_by_name(auto &&req, auto &&res) const; void handle_put_set_value_by_name(auto &&req, auto &&res) const;
void handle_put_settings(auto &&req, auto &&res) const;
auto launch_process(provider_type prov, std::string_view name, auto launch_process(provider_type prov, std::string_view name,
std::string_view args, bool background = false) const std::string_view args, bool background = false) const
-> std::vector<std::string>; -> std::vector<std::string>;

View File

@ -56,8 +56,12 @@ public:
std::string_view name) const std::string_view name) const
-> std::string; -> std::string;
void set_api_password(std::string_view api_password);
void set_api_port(std::uint16_t api_port); void set_api_port(std::uint16_t api_port);
void set_api_user(std::string_view api_user);
void set_mount_location(provider_type prov, std::string_view name, void set_mount_location(provider_type prov, std::string_view name,
std::string_view location); std::string_view location);
}; };

View File

@ -118,6 +118,10 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
handle_put_set_value_by_name(req, res); handle_put_set_value_by_name(req, res);
}); });
server->Put("/api/v1/settings", [this](auto &&req, auto &&res) {
handle_put_settings(req, res);
});
static std::atomic<httplib::Server *> this_server{server_}; static std::atomic<httplib::Server *> this_server{server_};
static const auto quit_handler = [](int /* sig */) { static const auto quit_handler = [](int /* sig */) {
auto *ptr = this_server.load(); auto *ptr = this_server.load();
@ -385,6 +389,25 @@ void handlers::handle_put_set_value_by_name(auto &&req, auto &&res) const {
res.status = http_error_codes::ok; res.status = http_error_codes::ok;
} }
void handlers::handle_put_settings(auto &&req, auto &&res) const {
nlohmann::json data = nlohmann::json::parse(req.get_param_value("data"));
if (data.contains(JSON_API_PASSWORD)) {
config_->set_api_password(data.at(JSON_API_PASSWORD).get<std::string>());
}
if (data.contains(JSON_API_PORT)) {
config_->set_api_port(
utils::string::to_uint16(data.at(JSON_API_PORT).get<std::string>()));
}
if (data.contains(JSON_API_USER)) {
config_->set_api_user(data.at(JSON_API_USER).get<std::string>());
}
res.status = http_error_codes::ok;
}
auto handlers::launch_process(provider_type prov, std::string_view name, auto handlers::launch_process(provider_type prov, std::string_view name,
std::string_view args, bool background) const std::string_view args, bool background) const
-> std::vector<std::string> { -> std::vector<std::string> {

View File

@ -147,6 +147,15 @@ void mgmt_app_config::save() const {
} }
} }
void mgmt_app_config::set_api_password(std::string_view api_password) {
if (api_password_ == std::string{api_password}) {
return;
}
api_password_ = std::string{api_password};
save();
}
void mgmt_app_config::set_api_port(std::uint16_t api_port) { void mgmt_app_config::set_api_port(std::uint16_t api_port) {
if (api_port_ == api_port) { if (api_port_ == api_port) {
return; return;
@ -156,6 +165,15 @@ void mgmt_app_config::set_api_port(std::uint16_t api_port) {
save(); save();
} }
void mgmt_app_config::set_api_user(std::string_view api_user) {
if (api_user_ == std::string{api_user}) {
return;
}
api_user_ = std::string{api_user};
save();
}
void mgmt_app_config::set_mount_location(provider_type prov, void mgmt_app_config::set_mount_location(provider_type prov,
std::string_view name, std::string_view name,
std::string_view location) { std::string_view location) {

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart' show GlobalKey, NavigatorState; import 'package:flutter/material.dart' show GlobalKey, NavigatorState;
const addMountTitle = 'Add New Mount'; const addMountTitle = 'Add New Mount';
const appSettingsTitle = 'Portal Settings';
const appTitle = 'Repertory Management Portal'; const appTitle = 'Repertory Management Portal';
const databaseTypeList = ['rocksdb', 'sqlite']; const databaseTypeList = ['rocksdb', 'sqlite'];
const downloadTypeList = ['default', 'direct', 'ring_buffer']; const downloadTypeList = ['default', 'direct', 'ring_buffer'];

View File

@ -52,7 +52,8 @@ class _MyAppState extends State<MyApp> {
'/add': '/add':
(context) => const AddMountScreen(title: constants.addMountTitle), (context) => const AddMountScreen(title: constants.addMountTitle),
'/settings': '/settings':
(context) => const EditSettingsScreen(title: constants.appTitle), (context) =>
const EditSettingsScreen(title: constants.appSettingsTitle),
}, },
onGenerateRoute: (settings) { onGenerateRoute: (settings) {
if (settings.name != '/edit') { if (settings.name != '/edit') {

View File

@ -26,12 +26,10 @@ void createBooleanSetting(
onPressed: onPressed:
(_) => setState(() { (_) => setState(() {
settings[key] = !value; settings[key] = !value;
widget.onChanged?.call(widget.settings);
}), }),
onToggle: (bool nextValue) { onToggle: (bool nextValue) {
setState(() { setState(() {
settings[key] = nextValue; settings[key] = nextValue;
widget.onChanged?.call(widget.settings);
}); });
}, },
), ),
@ -64,7 +62,6 @@ void createIntListSetting(
onChanged: (newValue) { onChanged: (newValue) {
setState(() { setState(() {
settings[key] = int.parse(newValue ?? defaultValue.toString()); settings[key] = int.parse(newValue ?? defaultValue.toString());
widget.onChanged?.call(widget.settings);
}); });
}, },
items: items:
@ -121,7 +118,6 @@ void createIntSetting(
} }
setState(() { setState(() {
settings[key] = int.parse(updatedValue); settings[key] = int.parse(updatedValue);
widget.onChanged?.call(widget.settings);
}); });
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@ -197,7 +193,6 @@ void createPasswordSetting(
setState(() { setState(() {
settings[key] = updatedValue1; settings[key] = updatedValue1;
widget.onChanged?.call(widget.settings);
}); });
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@ -279,7 +274,6 @@ void createStringListSetting(
onChanged: onChanged:
(newValue) => setState(() { (newValue) => setState(() {
settings[key] = newValue; settings[key] = newValue;
widget.onChanged?.call(widget.settings);
}), }),
items: items:
valueList.map<DropdownMenuItem<String>>((item) { valueList.map<DropdownMenuItem<String>>((item) {
@ -336,7 +330,6 @@ void createStringSetting(
} }
setState(() { setState(() {
settings[key] = updatedValue; settings[key] = updatedValue;
widget.onChanged?.call(widget.settings);
}); });
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },

View File

@ -13,13 +13,11 @@ class MountSettingsWidget extends StatefulWidget {
final bool isAdd; final bool isAdd;
final bool showAdvanced; final bool showAdvanced;
final Mount mount; final Mount mount;
final Function? onChanged;
final Map<String, dynamic> settings; final Map<String, dynamic> settings;
const MountSettingsWidget({ const MountSettingsWidget({
super.key, super.key,
this.isAdd = false, this.isAdd = false,
required this.mount, required this.mount,
this.onChanged,
required this.settings, required this.settings,
required this.showAdvanced, required this.showAdvanced,
}); });

View File

@ -1,21 +1,23 @@
import 'dart:convert' show jsonDecode, jsonEncode;
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:http/http.dart' as http;
import 'package:repertory/constants.dart' as constants;
import 'package:repertory/helpers.dart' import 'package:repertory/helpers.dart'
show getSettingDescription, getSettingValidators, trimNotEmptyValidator; show
import 'package:repertory/models/mount.dart'; convertAllToString,
import 'package:repertory/models/mount_list.dart'; getBaseUri,
getSettingDescription,
getSettingValidators,
trimNotEmptyValidator;
import 'package:repertory/settings.dart'; import 'package:repertory/settings.dart';
import 'package:settings_ui/settings_ui.dart'; import 'package:settings_ui/settings_ui.dart';
class UISettingsWidget extends StatefulWidget { class UISettingsWidget extends StatefulWidget {
final bool showAdvanced; final bool showAdvanced;
final Function? onChanged;
final Map<String, dynamic> settings; final Map<String, dynamic> settings;
const UISettingsWidget({ const UISettingsWidget({
super.key, super.key,
this.onChanged,
required this.settings, required this.settings,
required this.showAdvanced, required this.showAdvanced,
}); });
@ -25,6 +27,8 @@ class UISettingsWidget extends StatefulWidget {
} }
class _UISettingsWidgetState extends State<UISettingsWidget> { class _UISettingsWidgetState extends State<UISettingsWidget> {
late Map<String, dynamic> _origSettings;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<SettingsTile> commonSettings = []; List<SettingsTile> commonSettings = [];
@ -94,6 +98,32 @@ class _UISettingsWidgetState extends State<UISettingsWidget> {
); );
} }
@override
void dispose() {
if (!DeepCollectionEquality().equals(widget.settings, _origSettings)) {
http
.put(
Uri.parse(
Uri.encodeFull(
'${getBaseUri()}/api/v1/settings?data=${jsonEncode(convertAllToString(widget.settings))}',
),
),
)
.then((_) {})
.catchError((e) {
debugPrint('$e');
});
}
super.dispose();
}
@override
void initState() {
_origSettings = jsonDecode(jsonEncode(widget.settings));
super.initState();
}
@override @override
void setState(VoidCallback fn) { void setState(VoidCallback fn) {
if (!mounted) { if (!mounted) {