diff --git a/repertory/librepertory/include/types/repertory.hpp b/repertory/librepertory/include/types/repertory.hpp index 470d2bd7..52af2878 100644 --- a/repertory/librepertory/include/types/repertory.hpp +++ b/repertory/librepertory/include/types/repertory.hpp @@ -426,6 +426,7 @@ inline constexpr auto JSON_MAX_CONNECTIONS{"MaxConnections"}; inline constexpr auto JSON_MAX_UPLOAD_COUNT{"MaxUploadCount"}; inline constexpr auto JSON_MED_FREQ_INTERVAL_SECS{"MedFreqIntervalSeconds"}; inline constexpr auto JSON_META{"Meta"}; +inline constexpr auto JSON_MOUNT_AUTO_START{"MountAutoStart"}; inline constexpr auto JSON_MOUNT_LOCATIONS{"MountLocations"}; inline constexpr auto JSON_ONLINE_CHECK_RETRY_SECS{"OnlineCheckRetrySeconds"}; inline constexpr auto JSON_PATH{"Path"}; diff --git a/repertory/repertory/include/ui/handlers.hpp b/repertory/repertory/include/ui/handlers.hpp index 240a9b0f..8fa2d76b 100644 --- a/repertory/repertory/include/ui/handlers.hpp +++ b/repertory/repertory/include/ui/handlers.hpp @@ -104,6 +104,9 @@ private: void handle_post_mount(const httplib::Request &req, httplib::Response &res); + void handle_put_mount_auto_start(const httplib::Request &req, + httplib::Response &res) const; + void handle_put_mount_location(const httplib::Request &req, httplib::Response &res) const; diff --git a/repertory/repertory/include/ui/mgmt_app_config.hpp b/repertory/repertory/include/ui/mgmt_app_config.hpp index 02a07a7c..250bdfaa 100644 --- a/repertory/repertory/include/ui/mgmt_app_config.hpp +++ b/repertory/repertory/include/ui/mgmt_app_config.hpp @@ -42,6 +42,8 @@ private: std::unordered_map> locations_; + std::unordered_map> + mount_auto_start_; mutable std::recursive_mutex mtx_; private: @@ -60,6 +62,9 @@ public: [[nodiscard]] auto get_auto_start() const -> bool { return auto_start_; } + [[nodiscard]] auto get_auto_start(provider_type prov, + std::string_view name) const -> bool; + [[nodiscard]] auto get_hidden() const -> bool { return hidden_; } [[nodiscard]] auto get_launch_only() const -> bool { return launch_only_; } @@ -76,6 +81,9 @@ public: void set_auto_start(bool auto_start); + void set_auto_start(provider_type prov, std::string_view name, + bool auto_start); + void set_hidden(bool hidden); void set_launch_only(bool launch_only); diff --git a/repertory/repertory/src/ui/handlers.cpp b/repertory/repertory/src/ui/handlers.cpp index d91eddd8..3694c3ed 100644 --- a/repertory/repertory/src/ui/handlers.cpp +++ b/repertory/repertory/src/ui/handlers.cpp @@ -255,6 +255,10 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server) server->Post("/api/v1/mount", [this](auto &&req, auto &&res) { handle_post_mount(req, res); }); + server->Put("/api/v1/mount_auto_start", [this](auto &&req, auto &&res) { + handle_put_mount_auto_start(req, res); + }); + server->Put("/api/v1/mount_location", [this](auto &&req, auto &&res) { handle_put_mount_location(req, res); }); @@ -382,6 +386,21 @@ void handlers::generate_config(provider_type prov, std::string_view name, } } +void handlers::handle_put_mount_auto_start(const httplib::Request &req, + httplib::Response &res) const { + auto prov = provider_type_from_string(req.get_param_value("type")); + auto name = req.get_param_value("name"); + + if (not data_directory_exists(prov, name)) { + res.status = http_error_codes::not_found; + return; + } + + auto auto_start = utils::string::to_bool(req.get_param_value("auto_start")); + config_->set_auto_start(prov, name, auto_start); + res.status = http_error_codes::ok; +} + void handlers::handle_put_mount_location(const httplib::Request &req, httplib::Response &res) const { auto prov = provider_type_from_string(req.get_param_value("type")); @@ -523,6 +542,8 @@ void handlers::handle_get_mount_status(const httplib::Request &req, result.at("Location").get()); } + result["AutoStart"] = config_->get_auto_start(prov, name); + res.set_content(result.dump(), "application/json"); res.status = http_error_codes::ok; } diff --git a/repertory/repertory/src/ui/mgmt_app_config.cpp b/repertory/repertory/src/ui/mgmt_app_config.cpp index ad1f032b..7cc952bd 100644 --- a/repertory/repertory/src/ui/mgmt_app_config.cpp +++ b/repertory/repertory/src/ui/mgmt_app_config.cpp @@ -29,11 +29,12 @@ #include "utils/unix.hpp" namespace { +template [[nodiscard]] auto from_json(const nlohmann::json &json) -> std::unordered_map> { + std::unordered_map> { std::unordered_map> + std::unordered_map> map_of_maps{ {repertory::provider_type::encrypt, nlohmann::json::object()}, {repertory::provider_type::remote, nlohmann::json::object()}, @@ -97,7 +98,8 @@ mgmt_app_config::mgmt_app_config(bool hidden, bool launch_only) auto_start_ = data.contains(JSON_AUTO_START) ? data.at(JSON_AUTO_START).get() : false; - locations_ = from_json(data.at(JSON_MOUNT_LOCATIONS)); + mount_auto_start_ = from_json(data.at(JSON_MOUNT_AUTO_START)); + locations_ = from_json(data.at(JSON_MOUNT_LOCATIONS)); if (not data.contains(JSON_AUTO_START)) { save(); @@ -119,6 +121,17 @@ mgmt_app_config::mgmt_app_config(bool hidden, bool launch_only) } } +auto mgmt_app_config::get_auto_start(provider_type prov, + std::string_view name) const -> bool { + recur_mutex_lock lock(mtx_); + if (mount_auto_start_.contains(prov) && + mount_auto_start_.at(prov).contains(std::string{name})) { + return mount_auto_start_.at(prov).at(std::string{name}); + } + + return false; +} + auto mgmt_app_config::get_mount_location(provider_type prov, std::string_view name) const -> std::string { @@ -294,6 +307,22 @@ void mgmt_app_config::set_auto_start(bool auto_start) { save(); } +void mgmt_app_config::set_auto_start(provider_type prov, std::string_view name, + bool auto_start) { + if (name.empty()) { + return; + } + + recur_mutex_lock lock(mtx_); + if (mount_auto_start_[prov][std::string{name}] == auto_start) { + return; + } + + mount_auto_start_[prov][std::string{name}] = auto_start; + + save(); +} + auto mgmt_app_config::to_json() const -> nlohmann::json { nlohmann::json data; data[JSON_AUTO_START] = auto_start_; @@ -301,6 +330,7 @@ auto mgmt_app_config::to_json() const -> nlohmann::json { data[JSON_API_PORT] = api_port_; data[JSON_API_USER] = api_user_; data[JSON_MOUNT_LOCATIONS] = map_to_json(locations_); + data[JSON_MOUNT_AUTO_START] = map_to_json(mount_auto_start_); return data; } } // namespace repertory::ui diff --git a/web/repertory/lib/models/mount.dart b/web/repertory/lib/models/mount.dart index af4646de..e6a1d2e6 100644 --- a/web/repertory/lib/models/mount.dart +++ b/web/repertory/lib/models/mount.dart @@ -21,6 +21,7 @@ class Mount with ChangeNotifier { refresh(); } + bool get autoStart => mountConfig.autoStart; String? get bucket => mountConfig.bucket; String get id => '${type}_$name'; bool? get mounted => mountConfig.mounted; @@ -101,6 +102,35 @@ class Mount with ChangeNotifier { } } + Future setMountAutoStart(bool autoStart) async { + try { + mountConfig.autoStart = autoStart; + + final auth = await _auth.createAuth(); + final response = await http.put( + Uri.parse( + Uri.encodeFull( + '${getBaseUri()}/api/v1/mount_location?auth=$auth&name=$name&type=$type&auto_start=$autoStart', + ), + ), + ); + + if (response.statusCode == 401) { + _auth.logoff(); + return; + } + + if (response.statusCode == 404) { + _mountList?.reset(); + return; + } + + return refresh(); + } catch (e) { + debugPrint('$e'); + } + } + Future setMountLocation(String location) async { try { mountConfig.path = location; diff --git a/web/repertory/lib/types/mount_config.dart b/web/repertory/lib/types/mount_config.dart index b9e5534a..bb86e880 100644 --- a/web/repertory/lib/types/mount_config.dart +++ b/web/repertory/lib/types/mount_config.dart @@ -3,6 +3,7 @@ import 'package:repertory/helpers.dart' show initialCaps; class MountConfig { bool? mounted; + bool autoStart = false; final String _name; String path = ''; Map _settings = {}; @@ -30,6 +31,9 @@ class MountConfig { } void updateStatus(Map status) { + autoStart = status.containsKey('AutoStart') + ? status['AutoStart'] as bool + : false; path = status['Location'] as String; mounted = status['Active'] as bool; } diff --git a/web/repertory/lib/widgets/mount_widget.dart b/web/repertory/lib/widgets/mount_widget.dart index 619469fa..dcd7cae9 100644 --- a/web/repertory/lib/widgets/mount_widget.dart +++ b/web/repertory/lib/widgets/mount_widget.dart @@ -35,6 +35,11 @@ class _MountWidgetState extends State ); final subStyle = textTheme.bodyMedium?.copyWith(color: scheme.onSurface); + final visualDensity = VisualDensity( + horizontal: -VisualDensity.maximumDensity, + vertical: -(VisualDensity.maximumDensity * 2.0), + ); + return ConstrainedBox( constraints: const BoxConstraints(minHeight: 120), child: Card( @@ -141,6 +146,43 @@ class _MountWidgetState extends State style: subStyle, ), ), + IntrinsicWidth( + child: Theme( + data: Theme.of(context).copyWith( + listTileTheme: const ListTileThemeData( + contentPadding: EdgeInsets.zero, + horizontalTitleGap: 0, + minLeadingWidth: 0, + minVerticalPadding: 0, + ), + checkboxTheme: CheckboxThemeData( + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + visualDensity: visualDensity, + ), + ), + child: CheckboxListTile( + contentPadding: EdgeInsets.zero, + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + onChanged: (_) {}, + title: Row( + mainAxisSize: MainAxisSize.min, + children: const [ + Icon( + Icons.auto_mode, + size: constants.smallIconSize, + ), + SizedBox(width: constants.paddingSmall), + Text('Auto-mount'), + SizedBox(width: constants.paddingSmall), + ], + ), + value: mount.autoStart, + visualDensity: visualDensity, + ), + ), + ), ], ), ],