Skip to content

Commit 8d20359

Browse files
authored
feat: Plugins to NavBar (#63)
* feat: Plugins to NavBar * fix: No plugins message
1 parent 3fb5e59 commit 8d20359

10 files changed

Lines changed: 154 additions & 222 deletions

File tree

src/app/App.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ReactComponent as MoonIcon } from "../assets/moon.svg";
77
import { ReactComponent as PadlockUnlockedIcon } from "../assets/padlock-unlocked.svg";
88
import { ReactComponent as PadlockIcon } from "../assets/padlock.svg";
99
import { ReactComponent as PeersIcon } from "../assets/peers.svg";
10-
import { ReactComponent as SettingsIcon } from "../assets/settings.svg";
10+
import { ReactComponent as PluginsIcon } from "../assets/plugins.svg";
1111
import { ReactComponent as SunIcon } from "../assets/sun.svg";
1212
import { ReactComponent as VisualizerIcon } from "../assets/visualizer.svg";
1313
import { ServiceFactory } from "../factories/serviceFactory";
@@ -44,9 +44,9 @@ import Login from "./routes/Login";
4444
import Peer from "./routes/Peer";
4545
import { PeerRouteProps } from "./routes/PeerRouteProps";
4646
import Peers from "./routes/Peers";
47+
import Plugins from "./routes/Plugins";
4748
import Search from "./routes/Search";
4849
import { SearchRouteProps } from "./routes/SearchRouteProps";
49-
import Settings from "./routes/Settings";
5050
import Unavailable from "./routes/Unavailable";
5151
import Visualizer from "./routes/Visualizer";
5252

@@ -267,9 +267,9 @@ class App extends AsyncComponent<RouteComponentProps, AppState> {
267267
route: "/visualizer"
268268
},
269269
{
270-
label: "Settings",
271-
icon: <SettingsIcon />,
272-
route: "/settings",
270+
label: "Plugins",
271+
icon: <PluginsIcon />,
272+
route: "/plugins",
273273
hidden: !this.state.isLoggedIn
274274
},
275275
{
@@ -414,8 +414,8 @@ class App extends AsyncComponent<RouteComponentProps, AppState> {
414414
component={(props: RouteComponentProps) => (<Visualizer {...props} />)}
415415
/>
416416
<Route
417-
path="/settings"
418-
component={() => (<Settings />)}
417+
path="/plugins"
418+
component={() => (<Plugins />)}
419419
/>
420420
<Route
421421
path="/login"

src/app/components/plugins/Participation.tsx

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import classNames from "classnames";
22
import React, { ReactNode } from "react";
3-
import { ReactComponent as ParticipationIcon } from "../../../assets/plugins/spammer.svg";
43
import { ServiceFactory } from "../../../factories/serviceFactory";
54
import { IParticipationEvent } from "../../../models/plugins/participation/IParticipationEvent";
65
import { IParticipationEventInfo } from "../../../models/plugins/participation/IParticipationEventInfo";
@@ -72,14 +71,12 @@ class Participation extends AsyncComponent<unknown, ParticipationState> {
7271
* @returns The plugin details if available.
7372
*/
7473
public static pluginDetails(): {
75-
icon: ReactNode;
7674
title: string;
7775
description: string;
7876
settings: ReactNode;
7977
} | undefined {
8078
if (Participation._isAvailable) {
8179
return {
82-
icon: <ParticipationIcon />,
8380
title: Participation.PLUGIN_TITLE,
8481
description: Participation.PLUGIN_DESCRIPTION,
8582
settings: <Participation />
@@ -139,21 +136,18 @@ class Participation extends AsyncComponent<unknown, ParticipationState> {
139136
return (
140137
<div className="participation">
141138
<div className="content">
142-
<div className="row spread">
143-
<h2>{Participation.PLUGIN_TITLE}</h2>
144-
<div className="row">
145-
<button
146-
type="button"
147-
className="add-button"
148-
onClick={() => this.setState({
139+
<div className="row end">
140+
<button
141+
type="button"
142+
className="add-button"
143+
onClick={() => this.setState({
149144
dialogType: "add",
150145
dialogStatus: "",
151146
dialogBusy: false
152147
})}
153-
>
154-
Add Event
155-
</button>
156-
</div>
148+
>
149+
Add Event
150+
</button>
157151
</div>
158152
<div className="events-panel">
159153
{this.state.eventIds.length === 0 && (

src/app/components/plugins/Spammer.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React, { ReactNode } from "react";
2-
import { ReactComponent as SpammerIcon } from "../../../assets/plugins/spammer.svg";
32
import { ServiceFactory } from "../../../factories/serviceFactory";
43
import { ISpammerSettings } from "../../../models/plugins/ISpammerSettings";
54
import { AuthService } from "../../../services/authService";
@@ -81,14 +80,12 @@ class Spammer extends AsyncComponent<unknown, SpammerState> {
8180
* @returns The plugin details if available.
8281
*/
8382
public static pluginDetails(): {
84-
icon: ReactNode;
8583
title: string;
8684
description: string;
8785
settings: ReactNode;
8886
} | undefined {
8987
if (Spammer._isAvailable) {
9088
return {
91-
icon: <SpammerIcon />,
9289
title: Spammer.PLUGIN_TITLE,
9390
description: Spammer.PLUGIN_DESCRIPTION,
9491
settings: <Spammer />
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
@import '../../scss/fonts';
33
@import '../../scss/media-queries';
44

5-
.settings {
5+
.plugins {
66
display: flex;
77
flex: 1;
88
justify-content: center;
@@ -37,4 +37,13 @@
3737
}
3838
}
3939
}
40+
41+
a {
42+
color: var(--accent-primary);
43+
text-decoration: none;
44+
45+
&:hover {
46+
text-decoration: underline;
47+
}
48+
}
4049
}

src/app/routes/Plugins.tsx

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import React, { ReactNode } from "react";
2+
import { ServiceFactory } from "../../factories/serviceFactory";
3+
import { AuthService } from "../../services/authService";
4+
import AsyncComponent from "../components/layout/AsyncComponent";
5+
import TabPanel from "../components/layout/TabPanel";
6+
import Participation from "../components/plugins/Participation";
7+
import Spammer from "../components/plugins/Spammer";
8+
import "./Plugins.scss";
9+
import { PluginsState } from "./PluginsState";
10+
11+
/**
12+
* Plugins panel.
13+
*/
14+
class Plugins extends AsyncComponent<unknown, PluginsState> {
15+
/**
16+
* The auth service.
17+
*/
18+
private readonly _authService: AuthService;
19+
20+
/**
21+
* Create a new instance of Plugins.
22+
* @param props The props.
23+
*/
24+
constructor(props: unknown) {
25+
super(props);
26+
27+
this._authService = ServiceFactory.get<AuthService>("auth");
28+
29+
this.state = {
30+
plugins: []
31+
};
32+
}
33+
34+
/**
35+
* The component did mount.
36+
*/
37+
public async componentDidMount(): Promise<void> {
38+
super.componentDidMount();
39+
40+
const plugins = [];
41+
42+
if (this._authService.isLoggedIn()) {
43+
const pluginDetailsSpammer = Spammer.pluginDetails();
44+
if (pluginDetailsSpammer) {
45+
plugins.push(pluginDetailsSpammer);
46+
}
47+
const pluginDetailsParticipation = Participation.pluginDetails();
48+
if (pluginDetailsParticipation) {
49+
plugins.push(pluginDetailsParticipation);
50+
}
51+
}
52+
53+
if (plugins.length > 0) {
54+
this.setState({
55+
activeTab: plugins[0].title
56+
});
57+
}
58+
59+
this.setState({
60+
plugins
61+
});
62+
}
63+
64+
/**
65+
* Render the component.
66+
* @returns The node to render.
67+
*/
68+
public render(): ReactNode {
69+
return (
70+
<div className="plugins">
71+
<div className="content">
72+
{this.state.plugins.length === 0 && (
73+
<p className="margin-t-s">
74+
No plugins enabled which are supported by the dashboard.<br />
75+
More information about managing plugins can be found on the
76+
{" "}
77+
<a
78+
target="_blank"
79+
rel="noreferrer"
80+
href="https://wiki.iota.org/hornet/post_installation/managing_a_node#plugins"
81+
>
82+
Hornet Developer Documentation.
83+
</a>
84+
</p>
85+
)}
86+
<TabPanel
87+
tabs={this.state.plugins.map(p => p.title)}
88+
activeTab={this.state.activeTab ? this.state.activeTab : ""}
89+
onTabChanged={activeTab => {
90+
this.setState({
91+
activeTab
92+
});
93+
}}
94+
>
95+
{this.state.plugins.map((p, idx) => (
96+
<div data-label={p.title} key={idx}>
97+
{p.settings}
98+
</div>
99+
))}
100+
101+
</TabPanel>
102+
</div>
103+
</div >
104+
);
105+
}
106+
}
107+
108+
export default Plugins;

src/app/routes/PluginsState.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { ReactNode } from "react";
2+
3+
export interface PluginsState {
4+
5+
/**
6+
* The active tab.
7+
*/
8+
activeTab?: string;
9+
10+
/**
11+
* Plugins.
12+
*/
13+
plugins: {
14+
title: string;
15+
description: string;
16+
settings: ReactNode;
17+
}[];
18+
}

0 commit comments

Comments
 (0)