Skip to content

Commit

Permalink
Break down KVM list into header, table and cell components. (#1256)
Browse files Browse the repository at this point in the history
  • Loading branch information
Caleb Ellis authored Jun 16, 2020
1 parent fecc2f4 commit 5b96e87
Show file tree
Hide file tree
Showing 37 changed files with 817 additions and 233 deletions.
2 changes: 1 addition & 1 deletion ui/src/app/base/components/Meter/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

.p-meter__labels {
margin-bottom: 0;
padding-top: $sp-unit * .25;
padding-top: 0;
}
}
}
12 changes: 12 additions & 0 deletions ui/src/app/base/selectors/zone/zone.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { createSelector } from "@reduxjs/toolkit";

const zone = {};

/**
Expand Down Expand Up @@ -28,4 +30,14 @@ zone.loaded = (state) => state.zone.loaded;
*/
zone.errors = (state) => state.zone.errors;

/**
* Returns zone that matches given id
* @param {Object} state - The redux state.
* @param {Number} id - id of resource pool to return.
* @returns {Object} Resource pool that matches id.
*/
zone.getById = createSelector([zone.all, (state, id) => id], (zones, id) =>
zones.find((zone) => zone.id === id)
);

export default zone;
15 changes: 15 additions & 0 deletions ui/src/app/base/selectors/zone/zone.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,19 @@ describe("zone selectors", () => {
};
expect(zone.errors(state)).toStrictEqual("Data is incorrect");
});

it("can get a zone by id", () => {
const state = {
zone: {
items: [
{ name: "foo", id: 1 },
{ name: "bar", id: 2 },
],
},
};
expect(zone.getById(state, 1)).toStrictEqual({
name: "foo",
id: 1,
});
});
});
113 changes: 5 additions & 108 deletions ui/src/app/kvm/views/KVMList/KVMList.js
Original file line number Diff line number Diff line change
@@ -1,119 +1,16 @@
import { Col, Row, Spinner } from "@canonical/react-components";
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom";
import React from "react";

import { formatBytes } from "app/utils";
import { pod as podActions } from "app/base/actions";
import { pod as podSelectors } from "app/base/selectors";
import { useWindowTitle } from "app/base/hooks";
import Meter from "app/base/components/Meter";
import KVMListHeader from "./KVMListHeader";
import KVMListTable from "./KVMListTable";
import Section from "app/base/components/Section";

const KVMList = () => {
useWindowTitle("KVM");
const dispatch = useDispatch();

const pods = useSelector(podSelectors.all);
const podsLoading = useSelector(podSelectors.loading);

useEffect(() => {
dispatch(podActions.fetch());
}, [dispatch]);

return (
<Section title="KVM">
<Row>
<Col size={12}>
<div>
{podsLoading && (
<div className="u-align--center">
<Spinner text="Loading..." />
</div>
)}
<table>
<thead>
<tr>
<th>FQDN</th>
<th>Power</th>
<th>VM Host Type</th>
<th>VMs</th>
<th>OS</th>
<th>Resource Pool</th>
<th>CPU</th>
<th>RAM</th>
<th>Storage</th>
</tr>
</thead>
<tbody>
{pods.map((pod) => {
const usedMemory = formatBytes(pod.used.memory, "MiB", {
binary: true,
});
const usedStorage = formatBytes(pod.used.local_storage, "B");
return (
<tr key={pod.id}>
<td>
<Link to={`/kvm/${pod.id}`}>{pod.name}</Link>
</td>
<td>Unknown</td>
<td>Unknown</td>
<td>Unknown</td>
<td>Unknown</td>
<td>Unknown</td>
<td>
<Meter
className="u-no-margin--bottom"
data={[
{
key: `${pod.name}-cpu-meter`,
label: `${pod.total.cores}`,
value: pod.used.cores,
},
]}
labelsClassName="u-align--right"
max={pod.total.cores * pod.cpu_over_commit_ratio}
small
/>
</td>
<td>
<Meter
className="u-no-margin--bottom"
data={[
{
key: `${pod.name}-memory-meter`,
label: `${usedMemory.value} ${usedMemory.unit}`,
value: pod.used.memory,
},
]}
labelsClassName="u-align--right"
max={pod.total.memory * pod.memory_over_commit_ratio}
small
/>
</td>
<td>
<Meter
className="u-no-margin--bottom"
data={[
{
key: `${pod.name}-storage-meter`,
label: `${usedStorage.value} ${usedStorage.unit}`,
value: pod.used.local_storage,
},
]}
labelsClassName="u-align--right"
max={pod.total.local_storage}
small
/>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</Col>
</Row>
<Section title={<KVMListHeader />}>
<KVMListTable />
</Section>
);
};
Expand Down
124 changes: 0 additions & 124 deletions ui/src/app/kvm/views/KVMList/KVMList.test.js

This file was deleted.

40 changes: 40 additions & 0 deletions ui/src/app/kvm/views/KVMList/KVMListHeader/KVMListHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Spinner } from "@canonical/react-components";
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";

import { pod as podActions } from "app/base/actions";
import { pod as podSelectors } from "app/base/selectors";

const KVMListHeader = () => {
const dispatch = useDispatch();
const pods = useSelector(podSelectors.all);
const podsLoaded = useSelector(podSelectors.loaded);

useEffect(() => {
dispatch(podActions.fetch());
}, [dispatch]);

return (
<div className="u-flex--between u-flex--wrap">
<ul className="p-inline-list u-no-margin--bottom">
<li className="p-inline-list__item p-heading--four">KVM</li>
{podsLoaded ? (
<li
className="p-inline-list__item last-item u-text--light"
data-test="pod-count"
>
{`${pods.length} VM hosts available`}
</li>
) : (
<Spinner
className="u-no-padding u-no-margin"
inline
text="Loading..."
/>
)}
</ul>
</div>
);
};

export default KVMListHeader;
52 changes: 52 additions & 0 deletions ui/src/app/kvm/views/KVMList/KVMListHeader/KVMListHeader.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { mount } from "enzyme";
import { Provider } from "react-redux";
import { MemoryRouter } from "react-router-dom";
import configureStore from "redux-mock-store";
import React from "react";

import KVMListHeader from "./KVMListHeader";

const mockStore = configureStore();

describe("KVMListHeader", () => {
let initialState;
beforeEach(() => {
initialState = {
pod: {
loaded: true,
loading: false,
items: [{ id: 1 }, { id: 2 }],
},
};
});

it("displays a loader if pods have not loaded", () => {
const state = { ...initialState };
state.pod.loaded = false;
const store = mockStore(state);
const wrapper = mount(
<Provider store={store}>
<MemoryRouter initialEntries={[{ pathname: "/kvm", key: "testKey" }]}>
<KVMListHeader />
</MemoryRouter>
</Provider>
);
expect(wrapper.find("Spinner").exists()).toBe(true);
});

it("displays a pod count if pods have loaded", () => {
const state = { ...initialState };
state.pod.loaded = true;
const store = mockStore(state);
const wrapper = mount(
<Provider store={store}>
<MemoryRouter initialEntries={[{ pathname: "/kvm", key: "testKey" }]}>
<KVMListHeader />
</MemoryRouter>
</Provider>
);
expect(wrapper.find('[data-test="pod-count"]').text()).toBe(
"2 VM hosts available"
);
});
});
1 change: 1 addition & 0 deletions ui/src/app/kvm/views/KVMList/KVMListHeader/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./KVMListHeader";
Loading

0 comments on commit 5b96e87

Please sign in to comment.