Skip to content

Commit

Permalink
feat: show msm connection info
Browse files Browse the repository at this point in the history
Signed-off-by: Peter Makowski <peter.makowski@canonical.com>
  • Loading branch information
petermakowski committed Jun 11, 2024
1 parent cf672e2 commit 4dc3a7f
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 7 deletions.
14 changes: 14 additions & 0 deletions src/app/base/components/StatusBar/StatusBar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,17 @@ it("hides the feedback link in development environment", () => {
screen.queryByRole("button", { name: "Give feedback" })
).not.toBeInTheDocument();
});

it("displays the status message when connected to MAAS Site Manager", () => {
state.msm = factory.msmState({
status: factory.msmStatus({
running: "connected",
}),
});

renderWithMockStore(<StatusBar />, { state });

expect(
screen.getByText("Connected to MAAS Site Manager")
).toBeInTheDocument();
});
30 changes: 27 additions & 3 deletions src/app/base/components/StatusBar/StatusBar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { ReactNode } from "react";
import { useEffect, type ReactNode } from "react";

import { Button, Link } from "@canonical/react-components";
import { useSelector } from "react-redux";
import { Button, Icon, Link } from "@canonical/react-components";
import { useDispatch, useSelector } from "react-redux";

import TooltipButton from "../TooltipButton";

import { useUsabilla } from "@/app/base/hooks";
import configSelectors from "@/app/store/config/selectors";
Expand All @@ -18,6 +20,8 @@ import {
isDeployedWithHardwareSync,
isMachineDetails,
} from "@/app/store/machine/utils";
import { msmActions } from "@/app/store/msm";
import msmSelectors from "@/app/store/msm/selectors";
import type { UtcDatetime } from "@/app/store/types/model";
import { NodeStatus } from "@/app/store/types/node";
import { formatUtcDatetime, getTimeDistanceString } from "@/app/utils/time";
Expand Down Expand Up @@ -57,6 +61,12 @@ export const StatusBar = (): JSX.Element | null => {
const version = useSelector(versionSelectors.get);
const maasName = useSelector(configSelectors.maasName);
const allowUsabilla = useUsabilla();
const msmRunning = useSelector(msmSelectors.running);
const dispatch = useDispatch();

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

if (!(maasName && version)) {
return null;
Expand Down Expand Up @@ -101,6 +111,20 @@ export const StatusBar = (): JSX.Element | null => {
:&nbsp;
<span data-testid="status-bar-version">{version}</span>
</div>
<div className="p-status-bar__primary u-flex--no-shrink u-flex--wrap">
<span data-testid="status-bar-msm-status">
{msmRunning === "connected" ? (
<TooltipButton

Check failure on line 117 in src/app/base/components/StatusBar/StatusBar.tsx

View workflow job for this annotation

GitHub Actions / Test

src/app/base/components/StatusBar/StatusBar.test.tsx > can show if a machine is currently commissioning

ReferenceError: i__vite_ssr_import_meta__ is not defined ❯ StatusBar src/app/base/components/StatusBar/StatusBar.tsx:117:15 ❯ renderWithHooks node_modules/react-dom/cjs/react-dom.development.js:15486:18 ❯ mountIndeterminateComponent node_modules/react-dom/cjs/react-dom.development.js:20103:13 ❯ beginWork node_modules/react-dom/cjs/react-dom.development.js:21626:16 ❯ beginWork$1 node_modules/react-dom/cjs/react-dom.development.js:27465:14 ❯ performUnitOfWork node_modules/react-dom/cjs/react-dom.development.js:26599:12 ❯ workLoopSync node_modules/react-dom/cjs/react-dom.development.js:26505:5 ❯ renderRootSync node_modules/react-dom/cjs/react-dom.development.js:26473:7 ❯ recoverFromConcurrentError node_modules/react-dom/cjs/react-dom.development.js:25889:20 ❯ performConcurrentWorkOnRoot node_modules/react-dom/cjs/react-dom.development.js:25789:22

Check failure on line 117 in src/app/base/components/StatusBar/StatusBar.tsx

View workflow job for this annotation

GitHub Actions / Test

src/app/base/components/StatusBar/StatusBar.test.tsx > can show if a machine has not been commissioned yet

ReferenceError: i__vite_ssr_import_meta__ is not defined ❯ StatusBar src/app/base/components/StatusBar/StatusBar.tsx:117:15 ❯ renderWithHooks node_modules/react-dom/cjs/react-dom.development.js:15486:18 ❯ mountIndeterminateComponent node_modules/react-dom/cjs/react-dom.development.js:20103:13 ❯ beginWork node_modules/react-dom/cjs/react-dom.development.js:21626:16 ❯ beginWork$1 node_modules/react-dom/cjs/react-dom.development.js:27465:14 ❯ performUnitOfWork node_modules/react-dom/cjs/react-dom.development.js:26599:12 ❯ workLoopSync node_modules/react-dom/cjs/react-dom.development.js:26505:5 ❯ renderRootSync node_modules/react-dom/cjs/react-dom.development.js:26473:7 ❯ recoverFromConcurrentError node_modules/react-dom/cjs/react-dom.development.js:25889:20 ❯ performConcurrentWorkOnRoot node_modules/react-dom/cjs/react-dom.development.js:25789:22

Check failure on line 117 in src/app/base/components/StatusBar/StatusBar.tsx

View workflow job for this annotation

GitHub Actions / Test

src/app/base/components/StatusBar/StatusBar.test.tsx > can show the last time a machine was commissioned

ReferenceError: i__vite_ssr_import_meta__ is not defined ❯ StatusBar src/app/base/components/StatusBar/StatusBar.tsx:117:15 ❯ renderWithHooks node_modules/react-dom/cjs/react-dom.development.js:15486:18 ❯ mountIndeterminateComponent node_modules/react-dom/cjs/react-dom.development.js:20103:13 ❯ beginWork node_modules/react-dom/cjs/react-dom.development.js:21626:16 ❯ beginWork$1 node_modules/react-dom/cjs/react-dom.development.js:27465:14 ❯ performUnitOfWork node_modules/react-dom/cjs/react-dom.development.js:26599:12 ❯ workLoopSync node_modules/react-dom/cjs/react-dom.development.js:26505:5 ❯ renderRootSync node_modules/react-dom/cjs/react-dom.development.js:26473:7 ❯ recoverFromConcurrentError node_modules/react-dom/cjs/react-dom.development.js:25889:20 ❯ performConcurrentWorkOnRoot node_modules/react-dom/cjs/react-dom.development.js:25789:22

Check failure on line 117 in src/app/base/components/StatusBar/StatusBar.tsx

View workflow job for this annotation

GitHub Actions / Test

src/app/base/components/StatusBar/StatusBar.test.tsx > can handle an incorrectly formatted commissioning timestamp

ReferenceError: i__vite_ssr_import_meta__ is not defined ❯ StatusBar src/app/base/components/StatusBar/StatusBar.tsx:117:15 ❯ renderWithHooks node_modules/react-dom/cjs/react-dom.development.js:15486:18 ❯ mountIndeterminateComponent node_modules/react-dom/cjs/react-dom.development.js:20103:13 ❯ beginWork node_modules/react-dom/cjs/react-dom.development.js:21626:16 ❯ beginWork$1 node_modules/react-dom/cjs/react-dom.development.js:27465:14 ❯ performUnitOfWork node_modules/react-dom/cjs/react-dom.development.js:26599:12 ❯ workLoopSync node_modules/react-dom/cjs/react-dom.development.js:26505:5 ❯ renderRootSync node_modules/react-dom/cjs/react-dom.development.js:26473:7 ❯ recoverFromConcurrentError node_modules/react-dom/cjs/react-dom.development.js:25889:20 ❯ performConcurrentWorkOnRoot node_modules/react-dom/cjs/react-dom.development.js:25789:22

Check failure on line 117 in src/app/base/components/StatusBar/StatusBar.tsx

View workflow job for this annotation

GitHub Actions / Test

src/app/base/components/StatusBar/StatusBar.test.tsx > displays Last and Next sync instead of Last commissioned date for deployed machines with hardware sync enabled

ReferenceError: i__vite_ssr_import_meta__ is not defined ❯ StatusBar src/app/base/components/StatusBar/StatusBar.tsx:117:15 ❯ renderWithHooks node_modules/react-dom/cjs/react-dom.development.js:15486:18 ❯ mountIndeterminateComponent node_modules/react-dom/cjs/react-dom.development.js:20103:13 ❯ beginWork node_modules/react-dom/cjs/react-dom.development.js:21626:16 ❯ beginWork$1 node_modules/react-dom/cjs/react-dom.development.js:27465:14 ❯ performUnitOfWork node_modules/react-dom/cjs/react-dom.development.js:26599:12 ❯ workLoopSync node_modules/react-dom/cjs/react-dom.development.js:26505:5 ❯ renderRootSync node_modules/react-dom/cjs/react-dom.development.js:26473:7 ❯ recoverFromConcurrentError node_modules/react-dom/cjs/react-dom.development.js:25889:20 ❯ performConcurrentWorkOnRoot node_modules/react-dom/cjs/react-dom.development.js:25789:22

Check failure on line 117 in src/app/base/components/StatusBar/StatusBar.tsx

View workflow job for this annotation

GitHub Actions / Test

src/app/base/components/StatusBar/StatusBar.test.tsx > doesn't display last or next sync for deploying machines with hardware sync enabled

ReferenceError: i__vite_ssr_import_meta__ is not defined ❯ StatusBar src/app/base/components/StatusBar/StatusBar.tsx:117:15 ❯ renderWithHooks node_modules/react-dom/cjs/react-dom.development.js:15486:18 ❯ mountIndeterminateComponent node_modules/react-dom/cjs/react-dom.development.js:20103:13 ❯ beginWork node_modules/react-dom/cjs/react-dom.development.js:21626:16 ❯ beginWork$1 node_modules/react-dom/cjs/react-dom.development.js:27465:14 ❯ performUnitOfWork node_modules/react-dom/cjs/react-dom.development.js:26599:12 ❯ workLoopSync node_modules/react-dom/cjs/react-dom.development.js:26505:5 ❯ renderRootSync node_modules/react-dom/cjs/react-dom.development.js:26473:7 ❯ recoverFromConcurrentError node_modules/react-dom/cjs/react-dom.development.js:25889:20 ❯ performConcurrentWorkOnRoot node_modules/react-dom/cjs/react-dom.development.js:25789:22

Check failure on line 117 in src/app/base/components/StatusBar/StatusBar.tsx

View workflow job for this annotation

GitHub Actions / Test

src/app/base/components/StatusBar/StatusBar.test.tsx > displays correct text for machines with hardware sync enabled and no last_sync or next_sync

ReferenceError: i__vite_ssr_import_meta__ is not defined ❯ StatusBar src/app/base/components/StatusBar/StatusBar.tsx:117:15 ❯ renderWithHooks node_modules/react-dom/cjs/react-dom.development.js:15486:18 ❯ mountIndeterminateComponent node_modules/react-dom/cjs/react-dom.development.js:20103:13 ❯ beginWork node_modules/react-dom/cjs/react-dom.development.js:21626:16 ❯ beginWork$1 node_modules/react-dom/cjs/react-dom.development.js:27465:14 ❯ performUnitOfWork node_modules/react-dom/cjs/react-dom.development.js:26599:12 ❯ workLoopSync node_modules/react-dom/cjs/react-dom.development.js:26505:5 ❯ renderRootSync node_modules/react-dom/cjs/react-dom.development.js:26473:7 ❯ recoverFromConcurrentError node_modules/react-dom/cjs/react-dom.development.js:25889:20 ❯ performConcurrentWorkOnRoot node_modules/react-dom/cjs/react-dom.development.js:25789:22

Check failure on line 117 in src/app/base/components/StatusBar/StatusBar.tsx

View workflow job for this annotation

GitHub Actions / Test

src/app/base/components/StatusBar/StatusBar.test.tsx > displays last image sync timestamp for a rack or region+rack controller

ReferenceError: i__vite_ssr_import_meta__ is not defined ❯ StatusBar src/app/base/components/StatusBar/StatusBar.tsx:117:15 ❯ renderWithHooks node_modules/react-dom/cjs/react-dom.development.js:15486:18 ❯ mountIndeterminateComponent node_modules/react-dom/cjs/react-dom.development.js:20103:13 ❯ beginWork node_modules/react-dom/cjs/react-dom.development.js:21626:16 ❯ beginWork$1 node_modules/react-dom/cjs/react-dom.development.js:27465:14 ❯ performUnitOfWork node_modules/react-dom/cjs/react-dom.development.js:26599:12 ❯ workLoopSync node_modules/react-dom/cjs/react-dom.development.js:26505:5 ❯ renderRootSync node_modules/react-dom/cjs/react-dom.development.js:26473:7 ❯ recoverFromConcurrentError node_modules/react-dom/cjs/react-dom.development.js:25889:20 ❯ performConcurrentWorkOnRoot node_modules/react-dom/cjs/react-dom.development.js:25789:22

Check failure on line 117 in src/app/base/components/StatusBar/StatusBar.tsx

View workflow job for this annotation

GitHub Actions / Test

src/app/base/components/StatusBar/StatusBar.test.tsx > displays the feedback link when analytics enabled and not in development environment

ReferenceError: i__vite_ssr_import_meta__ is not defined ❯ StatusBar src/app/base/components/StatusBar/StatusBar.tsx:117:15 ❯ renderWithHooks node_modules/react-dom/cjs/react-dom.development.js:15486:18 ❯ mountIndeterminateComponent node_modules/react-dom/cjs/react-dom.development.js:20103:13 ❯ beginWork node_modules/react-dom/cjs/react-dom.development.js:21626:16 ❯ beginWork$1 node_modules/react-dom/cjs/react-dom.development.js:27465:14 ❯ performUnitOfWork node_modules/react-dom/cjs/react-dom.development.js:26599:12 ❯ workLoopSync node_modules/react-dom/cjs/react-dom.development.js:26505:5 ❯ renderRootSync node_modules/react-dom/cjs/react-dom.development.js:26473:7 ❯ recoverFromConcurrentError node_modules/react-dom/cjs/react-dom.development.js:25889:20 ❯ performConcurrentWorkOnRoot node_modules/react-dom/cjs/react-dom.development.js:25789:22
message="This MAAS is connected to a MAAS Site Manager.
It will regularly report to the Site Manager and choose
Site Manager as its upstream image source."
>
<Icon name="connected" />
Connected to MAAS Site Manager
</TooltipButton>
) : null}
</span>
</div>
<ul className="p-inline-list--middot u-no-margin--bottom">
<li className="p-inline-list__item">
<Link
Expand Down
1 change: 1 addition & 0 deletions src/app/store/msm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default, msmActions } from "./slice";
17 changes: 17 additions & 0 deletions src/app/store/msm/selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { createSelector } from "@reduxjs/toolkit";

import type { RootState } from "@/app/store/root/types";

const status = (state: RootState) => state.msm.status;
const running = createSelector(status, (status) => status?.running);
const loading = (state: RootState) => state.msm.loading;
const errors = (state: RootState) => state.msm.errors;

const msmSelectors = {
status,
running,
loading,
errors,
};

export default msmSelectors;
41 changes: 41 additions & 0 deletions src/app/store/msm/slice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { PayloadAction } from "@reduxjs/toolkit";
import { createSlice } from "@reduxjs/toolkit";

import type { MsmState, MsmStatus } from "./types/base";

import { genericInitialState } from "@/app/store/utils/slice";

const initialState: MsmState = {
...genericInitialState,
status: null,
};

const msmSlice = createSlice({
name: "msm",
initialState,
reducers: {
fetch: {
prepare: () => ({
meta: {
model: "msm",
method: "status",
},
payload: null,
}),
reducer: () => {},
},
fetchSuccess(state, action: PayloadAction<MsmStatus>) {
state.status = action.payload;
state.loading = false;
state.errors = null;
},
fetchError(state, action: PayloadAction<string>) {
state.errors = action.payload;
state.loading = false;
},
},
});

export const { actions: msmActions } = msmSlice;

export default msmSlice.reducer;
11 changes: 11 additions & 0 deletions src/app/store/msm/types/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface MsmStatus {
smUrl: string | null;
running: "not_connected" | "pending" | "connected";
startTime: string | null;
}

export interface MsmState {
status: MsmStatus | null;
loading: boolean;
errors: string | null;
}
3 changes: 3 additions & 0 deletions src/app/store/msm/types/enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum MsmMeta {
MODEL = "msm",
}
13 changes: 9 additions & 4 deletions src/app/store/root/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import type { RouterState } from "redux-first-history";

import type { ReservedIpState } from "../reservedip/types";
import type { ReservedIpMeta } from "../reservedip/types/enum";
import type { VMClusterMeta, VMClusterState } from "../vmcluster/types";

import type {
BootResourceState,
BootResourceMeta,
Expand Down Expand Up @@ -33,6 +29,8 @@ import type {
} from "@/app/store/licensekeys/types";
import type { MachineState, MachineMeta } from "@/app/store/machine/types";
import type { MessageState, MessageMeta } from "@/app/store/message/types";
import type { MsmState } from "@/app/store/msm/types/base";
import type { MsmMeta } from "@/app/store/msm/types/enum";
import type {
NodeDeviceState,
NodeDeviceMeta,
Expand All @@ -50,6 +48,8 @@ import type {
PackageRepositoryMeta,
} from "@/app/store/packagerepository/types";
import type { PodState, PodMeta } from "@/app/store/pod/types";
import type { ReservedIpState } from "@/app/store/reservedip/types";
import type { ReservedIpMeta } from "@/app/store/reservedip/types/enum";
import type {
ResourcePoolState,
ResourcePoolMeta,
Expand All @@ -73,6 +73,10 @@ import type { TagState, TagMeta } from "@/app/store/tag/types";
import type { TokenState, TokenMeta } from "@/app/store/token/types";
import type { UserState, UserMeta } from "@/app/store/user/types";
import type { VLANState, VLANMeta } from "@/app/store/vlan/types";
import type {
VMClusterMeta,
VMClusterState,
} from "@/app/store/vmcluster/types";
import type { ZoneState, ZoneMeta } from "@/app/store/zone/types";

export type RootState = {
Expand All @@ -90,6 +94,7 @@ export type RootState = {
[LicenseKeysMeta.MODEL]: LicenseKeysState;
[MachineMeta.MODEL]: MachineState;
[MessageMeta.MODEL]: MessageState;
[MsmMeta.MODEL]: MsmState;
[NodeDeviceMeta.MODEL]: NodeDeviceState;
[NodeScriptResultMeta.MODEL]: NodeScriptResultState;
[NotificationMeta.MODEL]: NotificationState;
Expand Down
3 changes: 3 additions & 0 deletions src/app/store/utils/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import type {
SliceCaseReducers,
} from "@reduxjs/toolkit";

import type { MsmMeta } from "../msm/types/enum";

import type { KeysOfUnion } from "@/app/base/types";
import type { BootResourceMeta } from "@/app/store/bootresource/types";
import type { ConfigMeta } from "@/app/store/config/types";
Expand Down Expand Up @@ -50,6 +52,7 @@ export type CommonStates = Omit<
| ConfigMeta.MODEL
| GeneralMeta.MODEL
| MessageMeta.MODEL
| MsmMeta.MODEL
| NodeScriptResultMeta.MODEL
| StatusMeta.MODEL
| ZoneMeta.MODEL
Expand Down
2 changes: 2 additions & 0 deletions src/root-reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import iprange from "@/app/store/iprange";
import licensekeys from "@/app/store/licensekeys";
import machine from "@/app/store/machine";
import message from "@/app/store/message";
import msm from "@/app/store/msm";
import nodedevice from "@/app/store/nodedevice";
import nodescriptresult from "@/app/store/nodescriptresult";
import notification from "@/app/store/notification";
Expand Down Expand Up @@ -61,6 +62,7 @@ const createAppReducer = (routerReducer: Reducer<RouterState, AnyAction>) =>
licensekeys,
machine,
message,
msm,
nodedevice,
nodescriptresult,
notification,
Expand Down
2 changes: 2 additions & 0 deletions src/testing/factories/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export {
machineStatus,
machineStatuses,
messageState,
msmState,
msmStatus,
nodeDeviceState,
nodeScriptResultState,
notificationState,
Expand Down
17 changes: 17 additions & 0 deletions src/testing/factories/msm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { define } from "cooky-cutter";

import { timestamp } from "./general";

import type { MsmState, MsmStatus } from "@/app/store/msm/types/base";

const msmStatus = define<MsmStatus>({
smUrl: "https://example.com",
running: "not_connected",
startTime: timestamp("Wed, 08 Jul. 2022 05:35:45"),
});

export const msm = define<MsmState>({
status: msmStatus(),
loading: false,
errors: null,
});
13 changes: 13 additions & 0 deletions src/testing/factories/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import type {
} from "@/app/store/machine/types";
import { FilterGroupKey, FilterGroupType } from "@/app/store/machine/types";
import type { MessageState } from "@/app/store/message/types";
import type { MsmState, MsmStatus } from "@/app/store/msm/types/base";
import type { NodeDeviceState } from "@/app/store/nodedevice/types";
import type { NodeScriptResultState } from "@/app/store/nodescriptresult/types";
import type { NotificationState } from "@/app/store/notification/types";
Expand Down Expand Up @@ -424,6 +425,17 @@ export const messageState = define<MessageState>({
items: () => [],
});

export const msmStatus = define<MsmStatus>({
running: "not_connected",
smUrl: "http://example.com",
startTime: "2021-01-01",
});
export const msmState = define<MsmState>({
status: msmStatus(),
loading: false,
errors: null,
});

export const architecturesState = define<ArchitecturesState>({
...defaultGeneralState,
});
Expand Down Expand Up @@ -681,6 +693,7 @@ export const rootState = define<RootState>({
licensekeys: licenseKeysState,
machine: machineState,
message: messageState,
msm: msmState,
nodedevice: nodeDeviceState,
notification: notificationState,
nodescriptresult: nodeScriptResultState,
Expand Down

0 comments on commit 4dc3a7f

Please sign in to comment.