Skip to content

Commit 0cea535

Browse files
authored
refactor(tui): Forward identity to gen ResourceBehaviour (#1976)
PR #1975 added the generated mechanical tier for the identity resources. Thin the hand-written `ResourceBehaviour` impls to one-line forwarders onto `super::generated::<r>::Generated::<method>`, keeping only custom logic: - `users.rs`: `action_to_request` enable/disable toggle, `confirm_request` delete prompt, `filter_carry_action` drilldown into application credentials, `handle_mutation_response`, and the two `TryFrom<&serde_json::Value>` builders. - `projects.rs`: `filter_carry_action` translating `SwitchToProject` into a `CloudChangeScope`. - `groups.rs`: `confirm_request` delete prompt, `filter_carry_action` drilldown into group users, and its two `TryFrom` builders. `group_users.rs` and `application_credentials.rs` are nested resources the generator does not emit and are left untouched. Test title expectations move to the generator's prefix-stripped form ("Users", "Projects", "Groups"). Assisted-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
1 parent de17bde commit 0cea535

3 files changed

Lines changed: 99 additions & 122 deletions

File tree

openstack_tui/src/components/identity/groups.rs

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,16 @@
1313
// SPDX-License-Identifier: Apache-2.0
1414

1515
use crate::action::Action;
16-
use crate::cloud_worker::identity::v3::{
17-
IdentityApiRequest, IdentityGroupApiRequest, IdentityGroupDelete, IdentityGroupDeleteBuilder,
18-
IdentityGroupList, IdentityGroupUserList, IdentityGroupUserListBuilder,
19-
};
20-
use crate::cloud_worker::types::ApiRequest;
16+
use crate::cloud_worker::types::{self as cloud_types, ApiRequest};
2117
use crate::components::generic_resource_view::GenericResourceView;
22-
use crate::components::resource_behaviour::ResourceBehaviour;
18+
use crate::components::resource_behaviour::{GeneratedResourceBehaviour, ResourceBehaviour};
2319
use crate::mode::Mode;
2420

25-
const VIEW_CONFIG_KEY: &str = "identity.group";
26-
27-
impl TryFrom<&serde_json::Value> for IdentityGroupUserList {
21+
impl TryFrom<&serde_json::Value> for cloud_types::IdentityGroupUserList {
2822
type Error = crate::cloud_worker::identity::v3::IdentityGroupUserListBuilderError;
2923
fn try_from(value: &serde_json::Value) -> Result<Self, Self::Error> {
30-
let mut builder = IdentityGroupUserListBuilder::default();
24+
let mut builder =
25+
crate::cloud_worker::identity::v3::IdentityGroupUserListBuilder::default();
3126
if let Some(val) = crate::components::view_render::get_str(value, "/id") {
3227
builder.group_id(val.to_string());
3328
}
@@ -38,10 +33,10 @@ impl TryFrom<&serde_json::Value> for IdentityGroupUserList {
3833
}
3934
}
4035

41-
impl TryFrom<&serde_json::Value> for IdentityGroupDelete {
36+
impl TryFrom<&serde_json::Value> for cloud_types::IdentityGroupDelete {
4237
type Error = crate::cloud_worker::identity::v3::IdentityGroupDeleteBuilderError;
4338
fn try_from(value: &serde_json::Value) -> Result<Self, Self::Error> {
44-
let mut builder = IdentityGroupDeleteBuilder::default();
39+
let mut builder = crate::cloud_worker::identity::v3::IdentityGroupDeleteBuilder::default();
4540
if let Some(val) = crate::components::view_render::get_str(value, "/id") {
4641
builder.id(val.to_string());
4742
}
@@ -55,26 +50,22 @@ impl TryFrom<&serde_json::Value> for IdentityGroupDelete {
5550
pub struct IdentityGroupsBehaviour;
5651

5752
impl ResourceBehaviour for IdentityGroupsBehaviour {
58-
type Filter = IdentityGroupList;
53+
type Filter = cloud_types::IdentityGroupList;
5954

6055
fn view_key() -> &'static str {
61-
VIEW_CONFIG_KEY
56+
super::generated::group::Generated::view_key()
6257
}
6358
fn title() -> &'static str {
64-
"Identity Groups"
59+
super::generated::group::Generated::title()
6560
}
6661
fn mode() -> Mode {
67-
Mode::Resource(Self::view_key())
62+
super::generated::group::Generated::mode()
6863
}
6964
fn request_from_filter(filter: &Self::Filter) -> ApiRequest {
70-
ApiRequest::from(IdentityGroupApiRequest::List(Box::new(filter.clone())))
65+
super::generated::group::Generated::request_from_filter(filter)
7166
}
7267
fn matches_request(request: &ApiRequest) -> bool {
73-
matches!(
74-
request,
75-
ApiRequest::Identity(IdentityApiRequest::Group(boxreq))
76-
if matches!(**boxreq, IdentityGroupApiRequest::List(_))
77-
)
68+
super::generated::group::Generated::matches_request(request)
7869
}
7970
fn confirm_request(
8071
action: &Action,
@@ -86,10 +77,10 @@ impl ResourceBehaviour for IdentityGroupsBehaviour {
8677
} = action
8778
&& *key == Self::view_key()
8879
{
89-
let del = IdentityGroupDelete::try_from(selected?).ok()?;
90-
Some(ApiRequest::from(IdentityGroupApiRequest::Delete(Box::new(
91-
del,
92-
))))
80+
let del = cloud_types::IdentityGroupDelete::try_from(selected?).ok()?;
81+
Some(ApiRequest::from(
82+
cloud_types::IdentityGroupApiRequest::Delete(Box::new(del)),
83+
))
9384
} else {
9485
None
9586
}
@@ -102,7 +93,7 @@ impl ResourceBehaviour for IdentityGroupsBehaviour {
10293
if let Action::ShowResource(key) = action
10394
&& *key == crate::mode::IDENTITY_GROUP_USER
10495
&& let Some(sel) = selected
105-
&& let Ok(list) = IdentityGroupUserList::try_from(sel)
96+
&& let Ok(list) = cloud_types::IdentityGroupUserList::try_from(sel)
10697
{
10798
return vec![
10899
Action::Mode {
@@ -135,7 +126,7 @@ mod tests {
135126
#[test]
136127
fn view_key_and_title() {
137128
assert_eq!(IdentityGroupsBehaviour::view_key(), "identity.group");
138-
assert_eq!(IdentityGroupsBehaviour::title(), "Identity Groups");
129+
assert_eq!(IdentityGroupsBehaviour::title(), "Groups");
139130
assert_eq!(
140131
IdentityGroupsBehaviour::mode(),
141132
Mode::Resource(crate::mode::IDENTITY_GROUP)
@@ -144,29 +135,29 @@ mod tests {
144135

145136
#[test]
146137
fn request_from_filter_creates_list_request() {
147-
let filter = IdentityGroupList::default();
138+
let filter = cloud_types::IdentityGroupList::default();
148139
let request = IdentityGroupsBehaviour::request_from_filter(&filter);
149140
assert!(matches!(
150141
request,
151-
ApiRequest::Identity(IdentityApiRequest::Group(boxreq))
152-
if matches!(*boxreq, IdentityGroupApiRequest::List(_))
142+
ApiRequest::Identity(cloud_types::IdentityApiRequest::Group(boxreq))
143+
if matches!(*boxreq, cloud_types::IdentityGroupApiRequest::List(_))
153144
));
154145
}
155146

156147
#[test]
157148
fn matches_request_returns_true_for_list() {
158-
let filter = IdentityGroupList::default();
149+
let filter = cloud_types::IdentityGroupList::default();
159150
let request = IdentityGroupsBehaviour::request_from_filter(&filter);
160151
assert!(IdentityGroupsBehaviour::matches_request(&request));
161152
}
162153

163154
#[test]
164155
fn matches_request_returns_false_for_unrelated() {
165-
let del = IdentityGroupDeleteBuilder::default()
156+
let del = crate::cloud_worker::identity::v3::IdentityGroupDeleteBuilder::default()
166157
.id("test".into())
167158
.build()
168159
.unwrap();
169-
let req = ApiRequest::from(IdentityGroupApiRequest::Delete(Box::new(del)));
160+
let req = ApiRequest::from(cloud_types::IdentityGroupApiRequest::Delete(Box::new(del)));
170161
assert!(!IdentityGroupsBehaviour::matches_request(&req));
171162
}
172163

@@ -184,8 +175,8 @@ mod tests {
184175
let request = result.unwrap();
185176
assert!(matches!(
186177
request,
187-
ApiRequest::Identity(IdentityApiRequest::Group(boxreq))
188-
if matches!(*boxreq, IdentityGroupApiRequest::Delete(_))
178+
ApiRequest::Identity(cloud_types::IdentityApiRequest::Group(boxreq))
179+
if matches!(*boxreq, cloud_types::IdentityGroupApiRequest::Delete(_))
189180
));
190181
}
191182

@@ -227,7 +218,7 @@ mod tests {
227218
let actions = IdentityGroupsBehaviour::filter_carry_action(
228219
&Action::ShowResource(crate::mode::IDENTITY_GROUP_USER),
229220
Some(&group),
230-
&IdentityGroupList::default(),
221+
&cloud_types::IdentityGroupList::default(),
231222
);
232223
assert_eq!(actions.len(), 2);
233224
assert!(matches!(
@@ -248,7 +239,7 @@ mod tests {
248239
let actions = IdentityGroupsBehaviour::filter_carry_action(
249240
&Action::ShowResource(crate::mode::IDENTITY_GROUP_USER),
250241
None,
251-
&IdentityGroupList::default(),
242+
&cloud_types::IdentityGroupList::default(),
252243
);
253244
assert!(actions.is_empty());
254245
}
@@ -259,7 +250,7 @@ mod tests {
259250
let actions = IdentityGroupsBehaviour::filter_carry_action(
260251
&Action::ShowResource(crate::mode::IDENTITY_GROUP),
261252
Some(&group),
262-
&IdentityGroupList::default(),
253+
&cloud_types::IdentityGroupList::default(),
263254
);
264255
assert!(actions.is_empty());
265256
}
@@ -270,7 +261,7 @@ mod tests {
270261
let actions = IdentityGroupsBehaviour::filter_carry_action(
271262
&Action::Tick,
272263
Some(&group),
273-
&IdentityGroupList::default(),
264+
&cloud_types::IdentityGroupList::default(),
274265
);
275266
assert!(actions.is_empty());
276267
}

openstack_tui/src/components/identity/projects.rs

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,30 @@
1313
// SPDX-License-Identifier: Apache-2.0
1414

1515
use crate::action::Action;
16-
use crate::cloud_worker::identity::v3::{
17-
IdentityApiRequest, IdentityProjectApiRequest, IdentityProjectList,
18-
};
19-
use crate::cloud_worker::types::ApiRequest;
16+
use crate::cloud_worker::types::{self as cloud_types, ApiRequest};
2017
use crate::components::generic_resource_view::GenericResourceView;
21-
use crate::components::resource_behaviour::ResourceBehaviour;
18+
use crate::components::resource_behaviour::{GeneratedResourceBehaviour, ResourceBehaviour};
2219
use crate::mode::Mode;
2320

24-
const VIEW_CONFIG_KEY: &str = "identity.project";
25-
2621
pub struct IdentityProjectsBehaviour;
2722

2823
impl ResourceBehaviour for IdentityProjectsBehaviour {
29-
type Filter = IdentityProjectList;
24+
type Filter = cloud_types::IdentityProjectList;
3025

3126
fn view_key() -> &'static str {
32-
VIEW_CONFIG_KEY
27+
super::generated::project::Generated::view_key()
3328
}
3429
fn title() -> &'static str {
35-
"Identity Projects"
30+
super::generated::project::Generated::title()
3631
}
3732
fn mode() -> Mode {
38-
Mode::Resource(Self::view_key())
33+
super::generated::project::Generated::mode()
3934
}
4035
fn request_from_filter(filter: &Self::Filter) -> ApiRequest {
41-
ApiRequest::from(IdentityProjectApiRequest::List(Box::new(filter.clone())))
36+
super::generated::project::Generated::request_from_filter(filter)
4237
}
4338
fn matches_request(request: &ApiRequest) -> bool {
44-
matches!(
45-
request,
46-
ApiRequest::Identity(IdentityApiRequest::Project(boxreq))
47-
if matches!(**boxreq, IdentityProjectApiRequest::List(_))
48-
)
39+
super::generated::project::Generated::matches_request(request)
4940
}
5041
fn filter_carry_action(
5142
action: &Action,
@@ -92,7 +83,7 @@ mod tests {
9283
#[test]
9384
fn view_key_and_title() {
9485
assert_eq!(IdentityProjectsBehaviour::view_key(), "identity.project");
95-
assert_eq!(IdentityProjectsBehaviour::title(), "Identity Projects");
86+
assert_eq!(IdentityProjectsBehaviour::title(), "Projects");
9687
assert_eq!(
9788
IdentityProjectsBehaviour::mode(),
9889
Mode::Resource(crate::mode::IDENTITY_PROJECT)
@@ -101,18 +92,18 @@ mod tests {
10192

10293
#[test]
10394
fn request_from_filter_creates_list_request() {
104-
let filter = IdentityProjectList::default();
95+
let filter = cloud_types::IdentityProjectList::default();
10596
let request = IdentityProjectsBehaviour::request_from_filter(&filter);
10697
assert!(matches!(
10798
request,
108-
ApiRequest::Identity(IdentityApiRequest::Project(boxreq))
109-
if matches!(*boxreq, IdentityProjectApiRequest::List(_))
99+
ApiRequest::Identity(cloud_types::IdentityApiRequest::Project(boxreq))
100+
if matches!(*boxreq, cloud_types::IdentityProjectApiRequest::List(_))
110101
));
111102
}
112103

113104
#[test]
114105
fn matches_request_returns_true_for_list() {
115-
let filter = IdentityProjectList::default();
106+
let filter = cloud_types::IdentityProjectList::default();
116107
let request = IdentityProjectsBehaviour::request_from_filter(&filter);
117108
assert!(IdentityProjectsBehaviour::matches_request(&request));
118109
}
@@ -123,7 +114,9 @@ mod tests {
123114
.id("test".into())
124115
.build()
125116
.unwrap();
126-
let req = ApiRequest::from(IdentityProjectApiRequest::Delete(Box::new(del)));
117+
let req = ApiRequest::from(cloud_types::IdentityProjectApiRequest::Delete(Box::new(
118+
del,
119+
)));
127120
assert!(!IdentityProjectsBehaviour::matches_request(&req));
128121
}
129122

@@ -133,7 +126,7 @@ mod tests {
133126
let actions = IdentityProjectsBehaviour::filter_carry_action(
134127
&Action::SwitchToProject,
135128
Some(&project),
136-
&IdentityProjectList::default(),
129+
&cloud_types::IdentityProjectList::default(),
137130
);
138131
assert_eq!(actions.len(), 1);
139132
assert!(matches!(actions[0], Action::CloudChangeScope(_)));
@@ -144,7 +137,7 @@ mod tests {
144137
let actions = IdentityProjectsBehaviour::filter_carry_action(
145138
&Action::SwitchToProject,
146139
None,
147-
&IdentityProjectList::default(),
140+
&cloud_types::IdentityProjectList::default(),
148141
);
149142
assert!(actions.is_empty());
150143
}
@@ -155,7 +148,7 @@ mod tests {
155148
let actions = IdentityProjectsBehaviour::filter_carry_action(
156149
&Action::Tick,
157150
Some(&project),
158-
&IdentityProjectList::default(),
151+
&cloud_types::IdentityProjectList::default(),
159152
);
160153
assert!(actions.is_empty());
161154
}

0 commit comments

Comments
 (0)