Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/release-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ jobs:
cp -r /clang64/share/themes "$bundle/share/" || true
mkdir -p "$bundle/share/aetheris"
cp data/style.css "$bundle/share/aetheris/style.css"
mkdir -p "$bundle/share/icons/hicolor/scalable/actions"
cp data/icons/hicolor/scalable/actions/*.svg "$bundle/share/icons/hicolor/scalable/actions/"
mkdir -p "$bundle/share/locale/pt_BR/LC_MESSAGES"
cp po/pt_BR/LC_MESSAGES/org.luminusos.Aetheris.mo "$bundle/share/locale/pt_BR/LC_MESSAGES/org.luminusos.Aetheris.mo"
cp -r /clang64/lib/gdk-pixbuf-2.0 "$bundle/lib/" || true
Expand Down
3 changes: 2 additions & 1 deletion build-aux/org.luminusos.Aetheris.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
"install -Dm644 data/icons/hicolor/256x256/apps/org.luminusos.Aetheris.png /app/share/icons/hicolor/256x256/apps/org.luminusos.Aetheris.png",
"install -Dm644 data/icons/hicolor/512x512/apps/org.luminusos.Aetheris.png /app/share/icons/hicolor/512x512/apps/org.luminusos.Aetheris.png",
"install -Dm644 data/icons/hicolor/symbolic/apps/org.luminusos.Aetheris-symbolic.svg /app/share/icons/hicolor/symbolic/apps/org.luminusos.Aetheris-symbolic.svg",
"install -Dm644 data/icons/hicolor/scalable/actions/nautilus-search-filters-symbolic.svg /app/share/icons/hicolor/scalable/actions/nautilus-search-filters-symbolic.svg"
"mkdir -p /app/share/icons/hicolor/scalable/actions",
"cp data/icons/hicolor/scalable/actions/*.svg /app/share/icons/hicolor/scalable/actions/"
],
"sources": [{ "type": "dir", "path": ".." }]
}
Expand Down
1 change: 1 addition & 0 deletions crates/aetheris-app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ assets = [
"../../data/icons/hicolor/256x256/apps/org.luminusos.Aetheris.png",
"../../data/icons/hicolor/512x512/apps/org.luminusos.Aetheris.png",
"../../data/icons/hicolor/symbolic/apps/org.luminusos.Aetheris-symbolic.svg",
"../../data/icons/hicolor/scalable/actions",
"../../po/pt_BR/LC_MESSAGES/org.luminusos.Aetheris.mo",
]
auto_link = true
Expand Down
10 changes: 7 additions & 3 deletions crates/aetheris-app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ mod yaml;

use i18n::{tr, tr_format, trn};
use projects::{
DetailTarget, ObjectColumn, ObjectTableColumn, PodLogTarget, Project, ProjectStore,
ResourceSection, StatusFilter,
DetailTarget, ObjectColumn, ObjectFavorite, ObjectTableColumn, PodLogTarget, Project,
ProjectStore, ResourceSection, StatusFilter,
};
use widgets::{
is_access_resource, is_cluster_resource, is_configuration_resource, is_network_resource,
Expand Down Expand Up @@ -83,6 +83,7 @@ pub(super) struct DetailPane {
apply_button: gtk::Button,
download_yaml_button: gtk::Button,
delete_button: gtk::Button,
favorite_button: gtk::Button,
terminal_button: gtk::Button,
yaml_buffer: sourceview5::Buffer,
events_list: gtk::ListBox,
Expand Down Expand Up @@ -168,6 +169,7 @@ pub struct App {
status_label: gtk::Label,
spinner: gtk::Spinner,
resource_list: gtk::ListBox,
favorite_object_list: gtk::ListBox,
/// Backing model for `object_view`. The `ColumnView` only realizes
/// widgets for on-screen rows, so this can hold tens of thousands of
/// objects without the widget tree growing with it.
Expand Down Expand Up @@ -254,7 +256,9 @@ pub enum AppMsg {
ObjectColumnToggled(u32),
ObjectColumnResized(ObjectTableColumn, i32),
EditCurrentCluster,
ResourceChanged(usize),
ResourceChanged(usize, ResourceSection),
ToggleCurrentObjectFavorite,
FavoriteObjectActivated(ObjectFavorite),
SearchChanged(String),
ObjectActivated(i32),
RelatedPodActivated(i32),
Expand Down
23 changes: 23 additions & 0 deletions crates/aetheris-app/src/app/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ impl Component for App {
let resource_list = gtk::ListBox::new();
resource_list.add_css_class("boxed-list");
resource_list.set_selection_mode(gtk::SelectionMode::None);
let favorite_object_list = gtk::ListBox::new();
favorite_object_list.add_css_class("boxed-list");
favorite_object_list.set_selection_mode(gtk::SelectionMode::None);
let object_store = gtk::gio::ListStore::new::<gtk::glib::BoxedAnyObject>();
let object_view = gtk::ColumnView::builder()
.single_click_activate(true)
Expand Down Expand Up @@ -333,6 +336,18 @@ impl Component for App {
detail_delete_button.add_css_class("flat");
detail_delete_button.set_size_request(34, 34);
detail_delete_button.set_valign(gtk::Align::Center);
let detail_favorite_button = gtk::Button::builder()
.icon_name(super::widgets::available_icon_name(
"aetheris-object-favorite-outline-symbolic",
"non-starred-symbolic",
))
.tooltip_text(tr("Add to favorites"))
.sensitive(false)
.visible(false)
.build();
detail_favorite_button.add_css_class("flat");
detail_favorite_button.set_size_request(34, 34);
detail_favorite_button.set_valign(gtk::Align::Center);
let detail_terminal_button = gtk::Button::builder()
.icon_name("utilities-terminal-symbolic")
.tooltip_text(tr("Open terminal"))
Expand Down Expand Up @@ -606,11 +621,13 @@ impl Component for App {
cluster_menu_button: &cluster_menu_button,
namespace_menu_button: &namespace_menu_button,
resource_list: &resource_list,
favorite_object_list: &favorite_object_list,
});
let content = build_content(ContentWidgets {
sidebar_toggle_button: &sidebar_toggle_button,
detail_back_button: &detail_back_button,
delete_button: &detail_delete_button,
favorite_button: &detail_favorite_button,
create_yaml_button: &create_yaml_button,
refresh_button: &refresh_button,
terminal_button: &detail_terminal_button,
Expand Down Expand Up @@ -813,6 +830,10 @@ impl Component for App {
let sender = sender.clone();
move |_| sender.input(AppMsg::DeleteObject)
});
detail_favorite_button.connect_clicked({
let sender = sender.clone();
move |_| sender.input(AppMsg::ToggleCurrentObjectFavorite)
});
detail_terminal_button.connect_clicked({
let sender = sender.clone();
move |_| sender.input(AppMsg::ShowPodTerminal)
Expand Down Expand Up @@ -916,6 +937,7 @@ impl Component for App {
status_label,
spinner,
resource_list,
favorite_object_list,
object_store,
object_sorted,
object_columns,
Expand All @@ -940,6 +962,7 @@ impl Component for App {
apply_button: detail_apply_button,
download_yaml_button: detail_download_yaml_button,
delete_button: detail_delete_button,
favorite_button: detail_favorite_button,
terminal_button: detail_terminal_button,
yaml_buffer: detail_yaml_buffer,
events_list: detail_events_list,
Expand Down
64 changes: 46 additions & 18 deletions crates/aetheris-app/src/app/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,22 +491,40 @@ impl App {
self.schedule_project_save(&sender);
}
}
AppMsg::ResourceChanged(index) => {
if self.resources.get(index).is_some() {
let next = Some(index);
if self.selected_resource != next {
self.selected_resource = next;
self.selected_resource_section =
ResourceSection::for_resource(&self.resources[index]);
self.rebuild_resource_list(Some(sender.clone()));
self.present_content_panel();
self.show_object_list();
self.sync_object_columns();
self.stop_log_stream();
self.stop_port_forward();
self.refresh_objects(sender);
}
AppMsg::ResourceChanged(index, _section) => {
let Some(resource) = self.resources.get(index) else {
return;
};
if self.selected_resource == Some(index) {
return;
}
self.selected_resource = Some(index);
self.selected_resource_section = ResourceSection::for_resource(resource);
self.rebuild_resource_list(Some(sender.clone()));
self.present_content_panel();
self.show_object_list();
self.sync_object_columns();
self.stop_log_stream();
self.stop_port_forward();
self.refresh_objects(sender);
}
AppMsg::ToggleCurrentObjectFavorite => {
let Some(target) = self.detail.target.clone() else {
return;
};
self.projects.toggle_object_favorite(&target);
self.save_projects_or_toast();
self.sync_detail_favorite_button();
self.rebuild_favorite_object_list(Some(sender.clone()));
}
AppMsg::FavoriteObjectActivated(favorite) => {
self.open_object_detail(
favorite.context.clone(),
favorite.resource(),
favorite.namespace(),
favorite.name.clone(),
sender,
);
}
AppMsg::SearchChanged(query) => {
self.search_query = query;
Expand Down Expand Up @@ -556,13 +574,19 @@ impl App {
return;
}
self.loading = false;
self.detail.target = None;
self.detail.log_target = None;
self.detail.exec_target = None;
self.detail.port_forward_target = None;
self.sync_log_controls();
self.sync_terminal_controls();
self.sync_port_forward_controls();
// Keep `target` set (rather than clearing it) and still open
// the detail page: the object is gone, but this is the only
// place with a favorite/star button, so a stale favorite
// must be reachable here to unfavorite it.
if let Some(target) = self.detail.target.clone() {
let placeholder = unavailable_object_detail(&target);
self.populate_detail_dialog(&placeholder);
self.show_detail_page(&placeholder.name);
}
self.status = tr("Unable to load object detail.");
self.sync_status();
self.toaster.add_toast(adw::Toast::new(&error));
Expand Down Expand Up @@ -617,6 +641,10 @@ impl App {
self.show_object_list();
self.stop_log_stream();
self.stop_port_forward();
self.detail.target = None;
self.detail.log_target = None;
self.detail.exec_target = None;
self.detail.port_forward_target = None;
self.sync_log_controls();
self.sync_terminal_controls();
self.sync_port_forward_controls();
Expand Down
70 changes: 66 additions & 4 deletions crates/aetheris-app/src/app/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub(super) struct SidebarWidgets<'a> {
pub(super) cluster_menu_button: &'a gtk::MenuButton,
pub(super) namespace_menu_button: &'a gtk::MenuButton,
pub(super) resource_list: &'a gtk::ListBox,
pub(super) favorite_object_list: &'a gtk::ListBox,
}

pub(super) fn build_sidebar(widgets: SidebarWidgets<'_>) -> adw::NavigationPage {
Expand All @@ -29,10 +30,69 @@ pub(super) fn build_sidebar(widgets: SidebarWidgets<'_>) -> adw::NavigationPage

container.append(&namespace_group);

let resources_group = gtk::Box::new(gtk::Orientation::Vertical, 8);
resources_group.append(&section_title(&tr("Resources")));
resources_group.append(widgets.resource_list);
container.append(&resources_group);
let resources_page = gtk::Box::new(gtk::Orientation::Vertical, 8);
resources_page.append(widgets.resource_list);

let favorites_page = gtk::Box::new(gtk::Orientation::Vertical, 8);
favorites_page.append(widgets.favorite_object_list);

let sidebar_stack = gtk::Stack::builder()
.hhomogeneous(false)
.vhomogeneous(false)
.build();
sidebar_stack.add_named(&resources_page, Some("resources"));
sidebar_stack.add_named(&favorites_page, Some("favorites"));

let toggle_box = gtk::Box::new(gtk::Orientation::Horizontal, 4);
let resources_toggle = gtk::ToggleButton::builder()
.icon_name("view-list-symbolic")
.tooltip_text(tr("Resources"))
.hexpand(true)
.active(true)
.css_classes(["flat"])
.build();
let favorites_toggle = gtk::ToggleButton::builder()
.icon_name("aetheris-object-favorite-symbolic")
.tooltip_text(tr("Favorites"))
.hexpand(true)
.css_classes(["flat"])
.build();
toggle_box.append(&resources_toggle);
toggle_box.append(&favorites_toggle);

resources_toggle.connect_clicked({
let resources_toggle = resources_toggle.clone();
move |_| resources_toggle.set_active(true)
});
resources_toggle.connect_toggled({
let favorites_toggle = favorites_toggle.clone();
let sidebar_stack = sidebar_stack.clone();
move |button| {
if button.is_active() {
favorites_toggle.set_active(false);
sidebar_stack.set_visible_child_name("resources");
}
}
});
favorites_toggle.connect_clicked({
let favorites_toggle = favorites_toggle.clone();
move |_| favorites_toggle.set_active(true)
});
favorites_toggle.connect_toggled({
let resources_toggle = resources_toggle.clone();
let sidebar_stack = sidebar_stack.clone();
move |button| {
if button.is_active() {
resources_toggle.set_active(false);
sidebar_stack.set_visible_child_name("favorites");
}
}
});

let objects_group = gtk::Box::new(gtk::Orientation::Vertical, 8);
objects_group.append(&toggle_box);
objects_group.append(&sidebar_stack);
container.append(&objects_group);

let scrolled = gtk::ScrolledWindow::builder()
.vexpand(true)
Expand All @@ -50,6 +110,7 @@ pub(super) struct ContentWidgets<'a> {
pub(super) sidebar_toggle_button: &'a gtk::ToggleButton,
pub(super) detail_back_button: &'a gtk::Button,
pub(super) delete_button: &'a gtk::Button,
pub(super) favorite_button: &'a gtk::Button,
pub(super) create_yaml_button: &'a gtk::Button,
pub(super) refresh_button: &'a gtk::Button,
pub(super) terminal_button: &'a gtk::Button,
Expand Down Expand Up @@ -101,6 +162,7 @@ pub(super) fn build_content(widgets: ContentWidgets<'_>) -> adw::NavigationPage
detail_actions.set_valign(gtk::Align::Center);
detail_actions.set_halign(gtk::Align::End);
detail_actions.append(widgets.terminal_button);
detail_actions.append(widgets.favorite_button);
detail_actions.append(widgets.delete_button);
header.pack_end(&detail_actions);
toolbar.add_top_bar(&header);
Expand Down
Loading
Loading