Skip to content

Commit 072c501

Browse files
committed
feat: update version to 1.1.0 and enhance namespace management
- Bump version for aetheris-app, aetheris-kube, and related files to 1.1.0. - Introduce functionality to manage custom namespaces, including adding, renaming, and removing namespaces. - Implement UI changes to support namespace management, including dialogs for renaming and adding namespaces. - Ensure that real-world identifiers are not used in code and documentation. - Add tests for namespace management functions to ensure reliability.
1 parent f49ffb4 commit 072c501

15 files changed

Lines changed: 632 additions & 94 deletions

File tree

AGENTS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ Never create commits, pull requests, tags, or push to any remote unless the user
66

77
Do not revert unrelated changes in the working tree. This repository often has active UI, packaging, and documentation work in progress.
88

9+
## No Real-World Identifiers
10+
11+
Never put real cluster names, namespace names, server hostnames, organization names, or other identifiers from an actual environment into code, comments, tests, or fixtures — including ones seen in bug reports, logs, or a real kubeconfig while debugging. This applies everywhere, not just test data: examples, placeholder text, error messages, sample YAML.
12+
13+
Always use clearly generic/fake values instead — `example.com`, `my-namespace`, `prod`, `console.example.com`, `payroll-hml` are fine; a real customer/org name or an actual internal hostname is not. If a bug reproduction naturally involves a real-looking name, invent a made-up equivalent before it lands in a commit.
14+
915
## Validation After Changes
1016

1117
Use the smallest validation that proves the change.

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ resolver = "2"
33
members = ["crates/aetheris-app", "crates/aetheris-kube"]
44

55
[workspace.package]
6-
version = "1.0.1"
6+
version = "1.1.0"
77
edition = "2021"
88
license = "GPL-3.0-or-later"
99
authors = ["Leandro Rodrigues <leandromqrs@hotmail.com>"]

build-aux/inno/aetheris.iss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
; SetupIconFile — optional .ico path
99

1010
#ifndef AppVersion
11-
#define AppVersion "1.0.1"
11+
#define AppVersion "1.1.0"
1212
#endif
1313
#ifndef SourceDir
1414
#define SourceDir "..\..\target\windows\aetheris"

crates/aetheris-app/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "aetheris-app"
33
description = "Aetheris native Kubernetes client for GNOME"
4-
version = "1.0.1"
4+
version = "1.1.0"
55
edition = "2021"
66
license = "GPL-3.0-or-later"
77
authors = ["Leandro Rodrigues <leandromqrs@hotmail.com>"]

crates/aetheris-app/src/app.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,15 @@ pub struct App {
230230
project_list: gtk::ListBox,
231231
project_title_label: gtk::Label,
232232
add_project_button: gtk::Button,
233+
projects_content_stack: gtk::Stack,
233234
cluster_back_button: gtk::Button,
234235
cluster_menu_button: gtk::MenuButton,
235236
cluster_refresh_button: gtk::Button,
236237
context_selector_label: gtk::Label,
237238
cluster_list: gtk::ListBox,
238239
add_cluster_button: gtk::Button,
239240
import_cluster_button: gtk::Button,
241+
clusters_content_stack: gtk::Stack,
240242
/// State/Provider/Version/CPU/Memory/Pods snapshot per context name,
241243
/// fetched lazily the first time the Clusters page shows a given
242244
/// context and cached until the app restarts.
@@ -314,11 +316,14 @@ pub struct App {
314316
port_forward_token: u64,
315317
port_forward_abort_handle: Option<AbortHandle>,
316318
custom_namespace_dialog: adw::Dialog,
317-
custom_namespace_entry: gtk::Entry,
319+
custom_namespace_entry: adw::EntryRow,
318320
custom_namespace_button: gtk::Button,
321+
rename_namespace_dialog: adw::Dialog,
322+
rename_namespace_entry: adw::EntryRow,
323+
rename_namespace_button: gtk::Button,
319324
project_dialog: adw::Dialog,
320325
project_dialog_description: gtk::Label,
321-
project_name_entry: gtk::Entry,
326+
project_name_entry: adw::EntryRow,
322327
project_create_button: gtk::Button,
323328
/// The project's name before this edit, when the project dialog is in
324329
/// rename mode. `None` means the dialog is creating a new project.
@@ -330,14 +335,17 @@ pub struct App {
330335
cluster_dialog_stack: gtk::Stack,
331336
cluster_token_title_label: gtk::Label,
332337
cluster_token_back_button: gtk::Button,
333-
setup_name_entry: gtk::Entry,
334-
setup_server_entry: gtk::Entry,
335-
setup_token_entry: gtk::PasswordEntry,
336-
setup_ca_entry: gtk::Entry,
337-
setup_insecure_check: gtk::CheckButton,
338+
setup_name_entry: adw::EntryRow,
339+
setup_server_entry: adw::EntryRow,
340+
setup_token_entry: adw::PasswordEntryRow,
341+
setup_ca_entry: adw::EntryRow,
342+
setup_insecure_check: adw::SwitchRow,
338343
setup_button: gtk::Button,
339344
editing_cluster: bool,
340345
editing_context_name: Option<String>,
346+
/// The namespace being renamed while `rename_namespace_dialog` is open.
347+
/// `None` means the dialog is closed.
348+
renaming_namespace: Option<String>,
341349
}
342350

343351
#[cfg(not(target_os = "windows"))]
@@ -370,6 +378,9 @@ pub enum AppMsg {
370378
ClusterSummaryLoaded(String, Result<ClusterSummary, String>),
371379
NamespaceChanged(u32),
372380
CustomNamespaceEntered,
381+
RemoveCustomNamespace(String),
382+
OpenRenameNamespaceDialog(String),
383+
RenameNamespaceConfirmed,
373384
StatusFilterChanged(u32),
374385
ObjectColumnToggled(u32),
375386
ObjectColumnResized(ObjectTableColumn, i32),

crates/aetheris-app/src/app/commands.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ pub(super) async fn load_cluster(context: String) -> AppMsg {
2424
let session = manager.connect_context(&context).await?;
2525
let (namespaces, namespace_warning) = match session.list_namespaces().await {
2626
Ok(namespaces) => (namespaces, None),
27-
Err(error) => (manager.namespaces(), Some(format_error(error))),
27+
Err(error) => (
28+
manager.namespace_for_context(&context),
29+
Some(format_error(error)),
30+
),
2831
};
2932
let resources = session.discover_resources().await?;
3033
Ok::<_, anyhow::Error>(ClusterState {

crates/aetheris-app/src/app/component.rs

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,25 @@ impl Component for App {
4949
.tooltip_text("Add project")
5050
.build();
5151
add_project_button.add_css_class("flat");
52+
let projects_empty_add_button = gtk::Button::builder()
53+
.child(
54+
&adw::ButtonContent::builder()
55+
.icon_name("list-add-symbolic")
56+
.label("Add Project")
57+
.build(),
58+
)
59+
.halign(gtk::Align::Center)
60+
.build();
61+
projects_empty_add_button.add_css_class("suggested-action");
62+
let projects_empty_page = adw::StatusPage::builder()
63+
.icon_name("folder-symbolic")
64+
.title("No Projects Yet")
65+
.description("Create a project to organize your clusters.")
66+
.valign(gtk::Align::Center)
67+
.vexpand(true)
68+
.build();
69+
projects_empty_page.set_child(Some(&projects_empty_add_button));
70+
let projects_content_stack = gtk::Stack::new();
5271
let context_selector_label = gtk::Label::new(Some("No cluster"));
5372
context_selector_label.set_ellipsize(gtk::pango::EllipsizeMode::End);
5473
context_selector_label.set_max_width_chars(22);
@@ -82,23 +101,48 @@ impl Component for App {
82101
.tooltip_text("Add cluster")
83102
.build();
84103
let import_cluster_button = gtk::Button::builder().label("Import").build();
104+
let clusters_empty_add_button = gtk::Button::builder()
105+
.child(
106+
&adw::ButtonContent::builder()
107+
.icon_name("list-add-symbolic")
108+
.label("Add Cluster")
109+
.build(),
110+
)
111+
.halign(gtk::Align::Center)
112+
.build();
113+
clusters_empty_add_button.add_css_class("suggested-action");
114+
let clusters_empty_page = adw::StatusPage::builder()
115+
.icon_name("network-server-symbolic")
116+
.title("No Clusters Yet")
117+
.description("Add a cluster to start browsing this project.")
118+
.valign(gtk::Align::Center)
119+
.vexpand(true)
120+
.build();
121+
clusters_empty_page.set_child(Some(&clusters_empty_add_button));
122+
let clusters_content_stack = gtk::Stack::new();
85123
let namespace_selector_label = gtk::Label::new(Some("default"));
86124
let namespace_menu_button = gtk::MenuButton::new();
87125
namespace_menu_button.set_size_request(170, -1);
88126
namespace_menu_button.set_child(Some(&selector_button_child(&namespace_selector_label)));
89127
let namespace_list = gtk::ListBox::new();
90128
namespace_menu_button.set_popover(Some(&selector_popover(&namespace_list)));
91-
let custom_namespace_entry = gtk::Entry::builder()
92-
.placeholder_text("my-namespace")
129+
let custom_namespace_entry = adw::EntryRow::builder()
130+
.title("Namespace")
93131
.hexpand(true)
94132
.build();
95133
let custom_namespace_button = gtk::Button::builder()
96134
.label("Use")
97135
.tooltip_text("Use and save this namespace")
98136
.build();
99137
custom_namespace_button.add_css_class("suggested-action");
100-
let project_name_entry = gtk::Entry::builder()
101-
.placeholder_text("Production")
138+
let rename_namespace_entry = adw::EntryRow::builder()
139+
.title("Namespace")
140+
.hexpand(true)
141+
.build();
142+
let rename_namespace_button = gtk::Button::builder().label("Rename").build();
143+
rename_namespace_button.add_css_class("suggested-action");
144+
let project_name_entry = adw::EntryRow::builder()
145+
.title("Project Name")
102146
.hexpand(true)
103147
.build();
104148
let project_create_button = gtk::Button::builder().label("Create").build();
@@ -389,25 +433,21 @@ impl Component for App {
389433
expand_logs_button: &detail_expand_logs_button,
390434
});
391435

392-
let setup_name_entry = gtk::Entry::builder()
393-
.placeholder_text("production")
394-
.hexpand(true)
395-
.build();
396-
let setup_server_entry = gtk::Entry::builder()
397-
.placeholder_text("https://127.0.0.1:6443")
436+
let setup_name_entry = adw::EntryRow::builder().title("Name").hexpand(true).build();
437+
let setup_server_entry = adw::EntryRow::builder()
438+
.title("API Server")
398439
.hexpand(true)
399440
.build();
400-
let setup_token_entry = gtk::PasswordEntry::builder()
401-
.placeholder_text("Bearer token")
441+
let setup_token_entry = adw::PasswordEntryRow::builder()
442+
.title("Bearer Token")
402443
.hexpand(true)
403-
.show_peek_icon(true)
404444
.build();
405-
let setup_ca_entry = gtk::Entry::builder()
406-
.placeholder_text("Optional base64 CA data")
445+
let setup_ca_entry = adw::EntryRow::builder()
446+
.title("CA Data")
407447
.hexpand(true)
408448
.build();
409-
let setup_insecure_check = gtk::CheckButton::builder()
410-
.label("Skip TLS verification")
449+
let setup_insecure_check = adw::SwitchRow::builder()
450+
.title("Skip TLS Verification")
411451
.build();
412452
let setup_button = gtk::Button::builder()
413453
.label("Add Cluster")
@@ -422,6 +462,8 @@ impl Component for App {
422462
open_dialog_button.add_css_class("suggested-action");
423463
let custom_namespace_dialog =
424464
build_custom_namespace_dialog(&custom_namespace_entry, &custom_namespace_button);
465+
let rename_namespace_dialog =
466+
build_rename_namespace_dialog(&rename_namespace_entry, &rename_namespace_button);
425467
let project_dialog = build_project_dialog(
426468
&project_name_entry,
427469
&project_create_button,
@@ -504,7 +546,12 @@ impl Component for App {
504546
split_view.set_content(Some(&content));
505547
root_stack.add_named(&build_empty_setup_page(&open_dialog_button), Some("setup"));
506548
root_stack.add_named(
507-
&build_projects_page(&project_list, &add_project_button),
549+
&build_projects_page(
550+
&project_list,
551+
&add_project_button,
552+
&projects_content_stack,
553+
&projects_empty_page,
554+
),
508555
Some("projects"),
509556
);
510557
root_stack.add_named(
@@ -516,6 +563,8 @@ impl Component for App {
516563
cluster_list: &cluster_list,
517564
add_cluster_button: &add_cluster_button,
518565
import_cluster_button: &import_cluster_button,
566+
content_stack: &clusters_content_stack,
567+
empty_page: &clusters_empty_page,
519568
}),
520569
Some("clusters"),
521570
);
@@ -554,6 +603,10 @@ impl Component for App {
554603
let sender = sender.clone();
555604
move |_| sender.input(AppMsg::ShowAddClusterDialog)
556605
});
606+
clusters_empty_add_button.connect_clicked({
607+
let sender = sender.clone();
608+
move |_| sender.input(AppMsg::ShowAddClusterDialog)
609+
});
557610
import_cluster_button.connect_clicked({
558611
let sender = sender.clone();
559612
move |_| sender.input(AppMsg::ShowImportFile)
@@ -570,14 +623,26 @@ impl Component for App {
570623
let sender = sender.clone();
571624
move |_| sender.input(AppMsg::ShowAddProjectDialog)
572625
});
573-
custom_namespace_entry.connect_activate({
626+
projects_empty_add_button.connect_clicked({
627+
let sender = sender.clone();
628+
move |_| sender.input(AppMsg::ShowAddProjectDialog)
629+
});
630+
custom_namespace_entry.connect_entry_activated({
574631
let sender = sender.clone();
575632
move |_| sender.input(AppMsg::CustomNamespaceEntered)
576633
});
577634
custom_namespace_button.connect_clicked({
578635
let sender = sender.clone();
579636
move |_| sender.input(AppMsg::CustomNamespaceEntered)
580637
});
638+
rename_namespace_entry.connect_entry_activated({
639+
let sender = sender.clone();
640+
move |_| sender.input(AppMsg::RenameNamespaceConfirmed)
641+
});
642+
rename_namespace_button.connect_clicked({
643+
let sender = sender.clone();
644+
move |_| sender.input(AppMsg::RenameNamespaceConfirmed)
645+
});
581646
status_filter_list.connect_child_activated({
582647
let sender = sender.clone();
583648
move |_, child| sender.input(AppMsg::StatusFilterChanged(child.index() as u32))
@@ -586,7 +651,7 @@ impl Component for App {
586651
let sender = sender.clone();
587652
move |_, child| sender.input(AppMsg::ObjectColumnToggled(child.index() as u32))
588653
});
589-
project_name_entry.connect_activate({
654+
project_name_entry.connect_entry_activated({
590655
let sender = sender.clone();
591656
move |_| sender.input(AppMsg::AddProject)
592657
});
@@ -752,13 +817,15 @@ impl Component for App {
752817
project_list,
753818
project_title_label,
754819
add_project_button,
820+
projects_content_stack,
755821
cluster_back_button,
756822
cluster_menu_button,
757823
cluster_refresh_button,
758824
context_selector_label,
759825
cluster_list,
760826
add_cluster_button,
761827
import_cluster_button,
828+
clusters_content_stack,
762829
cluster_summaries: std::collections::HashMap::new(),
763830
namespace_menu_button,
764831
namespace_selector_label,
@@ -835,6 +902,10 @@ impl Component for App {
835902
custom_namespace_dialog,
836903
custom_namespace_entry,
837904
custom_namespace_button,
905+
rename_namespace_dialog,
906+
rename_namespace_entry,
907+
rename_namespace_button,
908+
renaming_namespace: None,
838909
project_dialog,
839910
project_dialog_description,
840911
project_name_entry,

0 commit comments

Comments
 (0)