Skip to content

Commit

Permalink
VDisk list page added
Browse files Browse the repository at this point in the history
  • Loading branch information
archeoss committed Mar 3, 2024
1 parent 4a38f37 commit 258d12c
Show file tree
Hide file tree
Showing 16 changed files with 382 additions and 47 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ Bob Management GUI changelog
- Node list page, backend (#19)
- Home page, frontend (#22)
- Node list page, frontend (#23)
- VDisk list page, backend (#20)
2 changes: 2 additions & 0 deletions backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ impl Modify for SecurityAddon {
services::api::raw_configuration_by_node,
services::api::get_node_info,
services::api::get_nodes_list,
services::api::get_vdisk_info,
services::api::get_vdisks_list,
),
components(
schemas(models::shared::Credentials, models::shared::Hostname, models::shared::BobConnectionData,
Expand Down
16 changes: 2 additions & 14 deletions backend/src/models/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,8 @@ pub enum DiskProblem {
#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))]
#[tsync]
pub enum DiskStatus {
#[serde(rename = "good")]
Good,
#[serde(rename = "bad")]
Bad { problems: Vec<DiskProblem> },
#[serde(rename = "offline")]
Offline,
}

Expand All @@ -82,7 +79,6 @@ impl DiskStatus {

/// Defines disk status names
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Hash, EnumIter)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))]
#[tsync]
pub enum DiskStatusName {
Expand Down Expand Up @@ -190,11 +186,8 @@ impl NodeProblem {
#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))]
#[tsync]
pub enum NodeStatus {
#[serde(rename = "good")]
Good,
#[serde(rename = "bad")]
Bad { problems: Vec<NodeProblem> },
#[serde(rename = "offline")]
Offline,
}

Expand Down Expand Up @@ -227,7 +220,6 @@ impl TypedMetrics {

/// Defines node status names
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Hash, EnumIter)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))]
#[tsync]
pub enum NodeStatusName {
Expand Down Expand Up @@ -273,9 +265,7 @@ pub enum ReplicaProblem {
#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))]
#[tsync]
pub enum ReplicaStatus {
#[serde(rename = "good")]
Good,
#[serde(rename = "offline")]
Offline { problems: Vec<ReplicaProblem> },
}

Expand Down Expand Up @@ -330,6 +320,7 @@ impl Add for SpaceInfo {
/// Virtual disk Component
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))]
#[tsync]
pub struct VDisk {
pub id: u64,

Expand All @@ -347,17 +338,14 @@ pub struct VDisk {
/// Variants - Virtual Disk status
/// status == 'bad' when at least one of its replicas has problems
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
#[serde(tag = "status")]
// #[serde(tag = "status")]
#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))]
#[tsync]
// #[cfg_attr(all(feature = "swagger", debug_assertions),
// schema(example = json!({"status": "good"})))]
pub enum VDiskStatus {
#[serde(rename = "good")]
Good,
#[serde(rename = "bad")]
Bad,
#[serde(rename = "offline")]
Offline,
}

Expand Down
30 changes: 29 additions & 1 deletion backend/src/services/api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use super::prelude::*;
use super::{auth::HttpClient, prelude::*};

// TODO: For methods, that requires information from all nodes (/disks/count, /nodes/rps, etc.),
// think of better method of returning info
// another thread that constantly updates info in period and cache the results?

// TODO: For methods, that requires information from all nodes (/disks/count, /nodes/rps, etc.),
// think of better method of returning info
Expand Down Expand Up @@ -458,3 +462,27 @@ pub async fn raw_configuration_by_node(
.await?,
))
}

async fn get_client_by_node(

Check warning on line 466 in backend/src/services/api.rs

View workflow job for this annotation

GitHub Actions / gen-openapi

function `get_client_by_node` is never used

Check warning on line 466 in backend/src/services/api.rs

View workflow job for this annotation

GitHub Actions / gen-openapi

function `get_client_by_node` is never used
client: &HttpBobClient,
node_name: NodeName,
) -> AxumResult<Arc<HttpClient>> {
let nodes = fetch_nodes(client.api_main()).await?;

let node = nodes
.iter()
.find(|node| node.name == node_name)
.ok_or_else(|| {
tracing::error!("Couldn't find specified node");
APIError::RequestFailed
})?;

client
.cluster_with_addr()
.get(&node.name)
.ok_or_else(|| {
tracing::error!("Couldn't find specified node");
APIError::RequestFailed.into()
})
.cloned()
}
4 changes: 4 additions & 0 deletions backend/src/services/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ use api::{
use auth::{login, logout, require_auth, AuthState, BobUser, HttpBobClient, InMemorySessionStore};
use prelude::*;

use self::api::{get_vdisk_info, get_vdisks_list};

type BobAuthState = AuthState<
BobUser,
Uuid,
Expand All @@ -54,6 +56,8 @@ pub fn api_router_v1(auth_state: BobAuthState) -> Result<Router<BobAuthState>, R
.api_route("/nodes/space", &Method::GET, get_space)
.api_route("/nodes/list", &Method::GET, get_nodes_list)
.api_route("/nodes/:node_name", &Method::GET, get_node_info)
.api_route("/vdisks/list", &Method::GET, get_vdisks_list)
.api_route("/vdisks/:vdisk_id", &Method::GET, get_vdisk_info)
.api_route(
"/nodes/:node_name/metrics",
&Method::GET,
Expand Down
114 changes: 114 additions & 0 deletions frontend/src/components/VDiskList/VDiskList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { Context } from '@appTypes/context.ts';
import defaultTheme from '@layouts/DefaultTheme.ts';
import { Box, ThemeProvider } from '@mui/system';
import { useStore } from '@nanostores/react';
import axios from 'axios';
import React, { useCallback, useEffect, useMemo, useState } from 'react';

import FetchingBackdrop from '../backdrop/backdrop.tsx';
import VDiskTable from '../VDiskTable/VDiskTable.tsx';

const stubVDisk: VDisk = {
id: 0,
status: 'Offline',
partition_count: 0,
replicas: [],
};

axios.defaults.withCredentials = true;

const VDiskPage = () => {
const [vdisks, setVdisks] = useState<VDisk[]>([]);
const [vdiskList, setVdiskList] = useState<DTOVDisk[]>([]);
const [isPageLoaded, setIsPageLoaded] = useState(false);
const context = useStore(Context);

const fetchVdiskList = useMemo(
() => async () => {
try {
const [res] = await Promise.all([axios.get<DTOVDisk[]>('/api/v1/vdisks/list')]);
setVdisks(
res.data
.map((dtoVdisk: DTOVDisk) => {
return {
...stubVDisk,
id: dtoVdisk.id,
} as VDisk;
})
.sort((a, b) => (a.id < b.id ? -1 : 1)),
);
setVdiskList(res.data);
} catch (err) {
console.log(err);
}
},
[],
);

const fetchVdisk = useCallback(
(vdisk: number) => async () => {
try {
const [res] = await Promise.all([axios.get<VDisk>('/api/v1/vdisks/' + vdisk)]);
return res.data;
} catch (err) {
console.log(err);
}
},
[],
);
useEffect(() => {
fetchVdiskList();
}, [fetchVdiskList]);

useEffect(() => {
const fetchNodes = async () => {
const res = (
await Promise.all(
vdiskList.map(async (vdisk) => {
return fetchVdisk(vdisk.id)()
.catch(console.error)
.then((resultVdisk) => resultVdisk);
}),
)
).filter((vdisk): vdisk is VDisk => {
return typeof vdisk !== undefined;
});
setVdisks(res.concat(vdisks.filter((item) => !res.find((n) => (n?.id || '') == item.id))));
};
if (!isPageLoaded && vdiskList.length !== 0) {
fetchNodes();
setIsPageLoaded(true);
}
const interval = setInterval(() => {
fetchNodes();
}, context.refreshTime * 1000);

return () => clearInterval(interval);
}, [isPageLoaded, fetchVdisk, context.enabled, context.refreshTime, vdiskList, vdisks]);

if (!isPageLoaded) {
return <FetchingBackdrop />;
}
return (
<ThemeProvider theme={defaultTheme}>
<Box
sx={{
marginLeft: '52px',
marginRight: '52px',
marginTop: '38px',
'&:hover': {
color: '#282A2F',
},
height: '820px',
backgroundColor: '#1F2125',
borderColor: '#2E2E33',
border: '1',
}}
>
<VDiskTable vdisks={vdisks} />
</Box>
</ThemeProvider>
);
};

export default VDiskPage;
27 changes: 27 additions & 0 deletions frontend/src/components/VDiskTable/VDiskTable.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.greendot {
height: 16px;
width: 16px;
background-color: #34b663;
border-radius: 50%;
display: inline-block;
}

.reddot {
height: 16px;
width: 16px;
background-color: #c3234b;
border-radius: 50%;
display: inline-block;
}

.graydot {
height: 16px;
width: 16px;
background-color: #7b817e;
border-radius: 50%;
display: inline-block;
}

.greyHeader {
background-color: #35373c;
}
Loading

0 comments on commit 258d12c

Please sign in to comment.