(
State(state): State<DashboardState>,
Json(patch): Json<Value>,
)
| 95 | } |
| 96 | |
| 97 | pub(crate) async fn patch_user_settings( |
| 98 | State(state): State<DashboardState>, |
| 99 | Json(patch): Json<Value>, |
| 100 | ) -> ApiResult { |
| 101 | let patch = serde_json::from_value::<UserSettingsPatch>(patch) |
| 102 | .map_err(|err| patch_shape_error("user settings", &err))?; |
| 103 | |
| 104 | let mut errors = Vec::new(); |
| 105 | if let Some(debounce) = &patch.watcher_debounce { |
| 106 | if user_config::parse_duration(debounce).is_none() { |
| 107 | errors.push(validation_error( |
| 108 | "watcher_debounce", |
| 109 | "watcher_debounce must be a duration like \"2s\", \"15s\", or \"1m\"", |
| 110 | )); |
| 111 | } |
| 112 | } |
| 113 | if patch.extraction_timeout_secs == Some(0) { |
| 114 | errors.push(validation_error( |
| 115 | "extraction_timeout_secs", |
| 116 | "extraction_timeout_secs must be at least 1 second", |
| 117 | )); |
| 118 | } |
| 119 | if !errors.is_empty() { |
| 120 | return Err(validation_failed(&errors)); |
| 121 | } |
| 122 | |
| 123 | let mut config = UserConfig::load(); |
| 124 | let restart_recommended = patch |
| 125 | .watcher_debounce |
| 126 | .as_ref() |
| 127 | .is_some_and(|value| *value != config.watcher_debounce) |
| 128 | || patch |
| 129 | .extraction_timeout_secs |
| 130 | .is_some_and(|value| value != config.extraction_timeout_secs); |
| 131 | if let Some(upload_enabled) = patch.upload_enabled { |
| 132 | config.upload_enabled = upload_enabled; |
| 133 | } |
| 134 | if let Some(debounce) = patch.watcher_debounce { |
| 135 | config.watcher_debounce = debounce; |
| 136 | } |
| 137 | if let Some(timeout) = patch.extraction_timeout_secs { |
| 138 | config.extraction_timeout_secs = timeout; |
| 139 | } |
| 140 | if !config.save() { |
| 141 | return Err(internal_error(&"failed to save user config")); |
| 142 | } |
| 143 | |
| 144 | let mut payload = settings_payload(&state).await?; |
| 145 | payload["restart_recommended"] = json!(restart_recommended); |
| 146 | Ok(Json(payload)) |
| 147 | } |
| 148 | |
| 149 | async fn settings_payload(state: &DashboardState) -> std::result::Result<Value, JsonError> { |
| 150 | let project_config = load_config(&state.project_root).map_err(|err| internal_error(&err))?; |
nothing calls this directly
no test coverage detected