Skip to content

Commit

Permalink
feat: initial network page (#47)
Browse files Browse the repository at this point in the history
- note  the modal situation needs tidying up as it is currently messy
- failed deletion results in a slightly dodgy y/n modal where neither
can do anything...
  • Loading branch information
robertpsoane authored Jul 13, 2024
1 parent b496c3f commit 9548535
Show file tree
Hide file tree
Showing 14 changed files with 480 additions and 4 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ The following commands are supported:
| `images` | `image` | Open the `Images` top level page |
| `containers` | `container` | Open the `Containers` top level page |
| `volumes` | `volume` | Open the `Volumes` top level page |
| `networks` | `network` | Open the `Networks` top level page |
| `quit` | `q` | Close the application |


Expand Down Expand Up @@ -126,6 +127,17 @@ The following actions are available on the Volumes page:
| `Ctrl+d` | Delete the currently selected volume |
| `d` | Describe the currently selected volume |

#### Networks

The following actions are available on the Volumes page:

| Hotkey | Action |
| -------- | -------------------------------------- |
| `Ctrl+d` | Delete the currently selected volume |
| `d` | Describe the currently selected volume |

> :warning: **Network deletion isn't entirely complete**: A failed deletion currently results in a yes/no modal telling you that it couldn't be deleted. There is no difference between the yes and no results. This is due to the current modal story and a quick and dirty hack to get them set up. Once a generic modal exists this will be patched up!
#### Logs

The following actions are available on the Logs page:
Expand Down
23 changes: 23 additions & 0 deletions src/callbacks/delete_network.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::{docker::network::DockerNetwork, traits::Callback};
use async_trait::async_trait;
use color_eyre::eyre::Result;

#[derive(Debug)]
pub struct DeleteNetwork {
docker: bollard::Docker,
network: DockerNetwork,
}

impl DeleteNetwork {
pub fn new(docker: bollard::Docker, network: DockerNetwork) -> Self {
Self { docker, network }
}
}

#[async_trait]
impl Callback for DeleteNetwork {
async fn call(&self) -> Result<()> {
let _ = self.network.delete(&self.docker).await?;
Ok(())
}
}
25 changes: 25 additions & 0 deletions src/callbacks/empty_callable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::traits::Callback;
use async_trait::async_trait;
use color_eyre::eyre::Result;

#[derive(Debug)]
pub struct EmptyCallable {}

impl Default for EmptyCallable {
fn default() -> Self {
Self::new()
}
}

impl EmptyCallable {
pub fn new() -> Self {
Self {}
}
}

#[async_trait]
impl Callback for EmptyCallable {
async fn call(&self) -> Result<()> {
Ok(())
}
}
2 changes: 2 additions & 0 deletions src/callbacks/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod delete_container;
pub mod delete_image;
pub mod delete_network;
pub mod delete_volume;
pub mod empty_callable;
pub use delete_container::DeleteContainer;
5 changes: 4 additions & 1 deletion src/components/command_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const CONTAINER: &str = "container";
const CONTAINERS: &str = "containers";
const VOLUME: &str = "volume";
const VOLUMES: &str = "volumes";
const NETWORK: &str = "network";
const NETWORKS: &str = "networks";

#[derive(Debug)]
pub struct CommandInput {
Expand All @@ -33,7 +35,7 @@ pub struct CommandInput {
impl CommandInput {
pub fn new(tx: Sender<Message<Key, Transition>>, prompt: String) -> Self {
let ac: Autocomplete = Autocomplete::from(vec![
QUIT, Q, IMAGE, IMAGES, CONTAINER, CONTAINERS, VOLUME, VOLUMES,
QUIT, Q, IMAGE, IMAGES, CONTAINER, CONTAINERS, VOLUME, VOLUMES, NETWORK, NETWORKS,
]);
Self {
tx,
Expand Down Expand Up @@ -93,6 +95,7 @@ impl CommandInput {
IMAGE | IMAGES => Some(Transition::ToImagePage(AppContext::default())),
CONTAINER | CONTAINERS => Some(Transition::ToContainerPage(AppContext::default())),
VOLUME | VOLUMES => Some(Transition::ToVolumePage(AppContext::default())),
NETWORK | NETWORKS => Some(Transition::ToNetworkPage(AppContext::default())),
_ => None,
};

Expand Down
4 changes: 3 additions & 1 deletion src/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
docker::{
container::DockerContainer, image::DockerImage, traits::Describe, volume::DockerVolume,
container::DockerContainer, image::DockerImage, network::DockerNetwork, traits::Describe,
volume::DockerVolume,
},
events::Transition,
};
Expand All @@ -17,6 +18,7 @@ pub struct AppContext {
pub docker_container: Option<DockerContainer>,
pub docker_image: Option<DockerImage>,
pub docker_volume: Option<DockerVolume>,
pub docker_network: Option<DockerNetwork>,
pub describable: Option<Box<dyn Describe>>,
}

Expand Down
1 change: 1 addition & 0 deletions src/docker/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod container;
pub mod image;
pub mod logs;
pub mod network;
pub mod traits;
pub mod util;
pub mod volume;
66 changes: 66 additions & 0 deletions src/docker/network.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use bollard::secret::{Network, NetworkContainer};
use color_eyre::eyre::{bail, Result};
use serde::Serialize;
use std::collections::HashMap;

use super::traits::Describe;

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct DockerNetwork {
pub id: String,
pub name: String,
pub driver: String,
pub created_at: String,
pub scope: String,
pub internal: Option<bool>,
pub attachable: Option<bool>,
pub containers: Option<HashMap<String, NetworkContainer>>,
}

impl DockerNetwork {
pub fn from(v: Network) -> Self {
Self {
id: v.id.unwrap_or_default(),
name: v.name.unwrap_or_default(),
driver: v.driver.unwrap_or_default(),
created_at: v.created.unwrap_or_default(),
scope: v.scope.unwrap_or_default(),
internal: v.internal,
attachable: v.attachable,
containers: v.containers,
}
}

pub async fn list(docker: &bollard::Docker) -> Result<Vec<Self>> {
let networks = docker.list_networks::<String>(None).await?;
let mut network: Vec<Self> = networks.into_iter().map(Self::from).collect();

network.sort_by_key(|v| v.name.clone());

Ok(network)
}

pub async fn delete(&self, docker: &bollard::Docker) -> Result<()> {
docker.remove_network(&self.get_name()).await?;
Ok(())
}
}

impl Describe for DockerNetwork {
fn get_id(&self) -> String {
self.get_name()
}
fn get_name(&self) -> String {
self.name.clone()
}

fn describe(&self) -> Result<Vec<String>> {
let summary = match serde_yml::to_string(&self) {
Ok(s) => s,
Err(_) => {
bail!("failed to parse container summary")
}
};
Ok(summary.lines().map(String::from).collect())
}
}
1 change: 1 addition & 0 deletions src/events/transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub enum Transition {
ToDescribeContainerPage(AppContext),
ToAttach(AppContext),
ToVolumePage(AppContext),
ToNetworkPage(AppContext),
}

pub async fn send_transition(
Expand Down
3 changes: 2 additions & 1 deletion src/pages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ pub mod containers;
pub mod describe;
pub mod images;
pub mod logs;
pub mod volume;
pub mod networks;
pub mod volumes;
Loading

0 comments on commit 9548535

Please sign in to comment.