Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Telegram channel id on ethical metrics implementation #1890

Merged
merged 32 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f08ca8f
tgChannelId field on system notifications
mateumiralles Mar 13, 2024
b733d88
updated welcome modal with telegram new info
GiselleNessi Mar 13, 2024
b2896dd
Merge branch 'gi/welcome-modal-ethical-metrics' into mateu/telegram-c…
mateumiralles Mar 13, 2024
b34f82b
variables unificated
mateumiralles Mar 13, 2024
2535c88
style corrections
mateumiralles Mar 14, 2024
c10b191
updated logic for inputs and buttons
GiselleNessi Mar 14, 2024
f05b67a
Merge branch 'mateu/telegram-channel-id-input' of github.com:dappnode…
GiselleNessi Mar 14, 2024
79eb0a5
updated style for accordion
GiselleNessi Mar 14, 2024
63679f8
remove unnecesary imports
GiselleNessi Mar 14, 2024
f469045
updated style for accordion
GiselleNessi Mar 14, 2024
564e930
modal modifications
mateumiralles Mar 14, 2024
a0b2d6e
style conflict fix
mateumiralles Mar 14, 2024
fea766b
simplifies the function by directly using the state variables
GiselleNessi Mar 15, 2024
13e2bd9
Modal trigger switch fix
mateumiralles Mar 15, 2024
f0f77a6
separate function to encapsulate the disabled conditions enhancing it…
GiselleNessi Mar 15, 2024
373962c
revert changes to fix build error
GiselleNessi Mar 15, 2024
545eb5d
Refactored EnableEthicalMetrics component, simplified function and st…
GiselleNessi Mar 15, 2024
e5d714f
Improved UX with docs redirection
GiselleNessi Mar 19, 2024
268704c
Disabled update button on regex match or no changes. Added post-updat…
GiselleNessi Mar 19, 2024
0f96394
Refactor button disable conditions for clarity and readability
GiselleNessi Mar 19, 2024
071f367
Ethical metrics System / Notification changes
mateumiralles Mar 19, 2024
31935a6
Updating values in the UI when revalidating
mateumiralles Mar 19, 2024
e0d8089
Ethical metrics copy modified on system / notifications
mateumiralles Mar 19, 2024
3fe1dc7
modal retriggered and db key "notifications" instead of "ethical-metr…
mateumiralles Mar 19, 2024
2aee5a9
Merge pull request #1895 from dappnode/mateu/system-notifications-mod…
mateumiralles Mar 20, 2024
221a138
Merge pull request #1894 from dappnode/gi/ethical-metrics-enhancement
mateumiralles Mar 20, 2024
59fa0a9
updated accordion position and useffect default value
GiselleNessi Mar 20, 2024
7b13a27
Switch pointer and email or tgChannelId required on modal
mateumiralles Mar 20, 2024
6e95db8
Deleting wasEthicalMetrics on from modal, and changing accordion tele…
mateumiralles Mar 21, 2024
2fd9f04
Accordion improvements
mateumiralles Mar 25, 2024
60bde81
target _blank fix
mateumiralles Mar 26, 2024
291bb63
Merge branch 'develop' into mateu/telegram-channel-id-input
pablomendezroyo Apr 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 19 additions & 18 deletions packages/admin-ui/src/components/SwitchBig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,39 @@ import React from "react";
import Switch from "react-switch";
import "./switchBig.scss";

const factor = 2;
const height = 28 * factor;
const width = 64 * factor;
const fontSize = 16 * factor;
const onColor = "#00b1f4";
const offColor = undefined; // "#bc2f39";
const switchLabelProps = {
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100%",
fontSize,
color: "white",
paddingRight: 2
};

export default function SwitchBig({
id,
label,
checked,
onChange,
disabled
disabled,
factor = 1.5
}: {
id: string;
label: string;
checked: boolean;
onChange: (bool: boolean) => void;
disabled?: boolean;
factor?: number;
}) {
const labelClass = checked ? "blue-text" : "";
const height = 28 * factor;
const width = 64 * factor;
const fontSize = 16 * factor;
const onColor = "#00b1f4";
const offColor = undefined; // "#bc2f39";
const switchLabelProps = {
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100%",
fontSize,
color: "white",
paddingRight: 2
};
return (
<label htmlFor={id} className="switch-big">
<span>{label}</span>
<span className={labelClass}>{label}</span>
<Switch
disabled={disabled}
checked={checked}
Expand Down
2 changes: 1 addition & 1 deletion packages/admin-ui/src/components/sidebar/sidebar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@

span {
font-weight: bold;
color: #0aa1da;
color: var(--dappnode-strong-main-color);
}
}

Expand Down
7 changes: 7 additions & 0 deletions packages/admin-ui/src/components/switchBig.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ label.switch-big {
order: 2;
font-size: 0.85rem;
margin-top: 0.15rem;
}

> .react-switch {
cursor: pointer;
}
}

.blue-text {
color: #00b1f4;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import React, { useEffect, useState } from "react";
import BottomButtons from "../BottomButtons";
import SwitchBig from "components/SwitchBig";
import { api } from "api";
import { api, useApi } from "api";
import Input from "components/Input";
import { docsUrl } from "params";
import Button from "components/Button";
import { Accordion } from "react-bootstrap";
import { BsInfoCircleFill } from "react-icons/bs";
import { IoIosArrowUp, IoIosArrowDown } from "react-icons/io";
import "./enableEthicalMetrics.scss";

export default function EnableEthicalMetrics({
onBack,
Expand All @@ -12,43 +17,202 @@ export default function EnableEthicalMetrics({
onBack?: () => void;
onNext: () => void;
}) {
const ethicalMetricsConfig = useApi.getEthicalMetricsConfig();
const [ethicalMetricsOn, setEthicalMetricsOn] = useState(false);
const [mail, setMail] = useState("");
const [mailError, setMailError] = useState(false);
const [tgChannelId, setTgChannelId] = useState("");
const [tgChannelIdError, setTgChannelIdError] = useState(false);
const [validationMessage, setValidationMessage] = useState("");
const [tgAccordionOpen, setTgAccordionOpen] = useState(false);

// regex for email validation
// useEffect to populate email field when data is available
useEffect(() => {
const ethicalMetricsData = ethicalMetricsConfig.data;
if (ethicalMetricsData) {
setMail(ethicalMetricsData.mail || "");
setTgChannelId(ethicalMetricsData.tgChannelId || "");
setEthicalMetricsOn(ethicalMetricsData.enabled);
}
}, [ethicalMetricsConfig.data]);

// effect and regex for email validation
useEffect(() => {
const regex = /\S+@\S+\.\S+/;
if (regex.test(mail)) {
if (regex.test(mail) || mail === "") {
setMailError(false);
setEthicalMetricsOn(true);
} else {
setMailError(true);
setEthicalMetricsOn(false);
}
}, [mail]);

function onSetEnabeEthicalMetrics() {
if (ethicalMetricsOn)
api
.enableEthicalMetrics({ mail, tgChannelId: null, sync: false })
.catch(e => {
console.error(`Error on autoUpdateSettingsEdit : ${e.stack}`);
});
onNext();
// effect and regex for telegram channelId validation
useEffect(() => {
const regex = /^-100\d{10}$/;
if (regex.test(tgChannelId) || tgChannelId === "") {
setTgChannelIdError(false);
} else {
setTgChannelIdError(true);
}
}, [tgChannelId]);

async function enableEthicalMetricsSync() {
try {
setValidationMessage("Enabling ethical metrics...");
await api.enableEthicalMetrics({
mail: mail ? mail : null,
tgChannelId: tgChannelId ? tgChannelId : null,
sync: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you test the behaviour of setting this with option sync to true? Take into account that this might be the onboarding and might take some time the user would not like to wait during setting up dappnode

});
setEthicalMetricsOn(true);
setValidationMessage("Ethical metrics enabled successfully.");
await ethicalMetricsConfig.revalidate();
} catch (error) {
setValidationMessage("Error enabling ethical metrics.");
console.error("Error enabling ethical metrics:", error);
}
}

// clear the success message after 5 seconds
useEffect(() => {
if (validationMessage === "Ethical metrics enabled successfully.") {
const timer = setTimeout(() => {
setValidationMessage("");
}, 5000);
return () => clearTimeout(timer);
}
}, [validationMessage]);

function toggleEthicalSwitch() {
if (!ethicalMetricsOn) {
enableEthicalMetricsSync();
}
setEthicalMetricsOn(!ethicalMetricsOn);
}

return (
<>
<div className="ethical-container">
<div className="header">
<div className="title">Enable system notifications</div>
<div className="title">Enable System Notifications</div>
<div className="description">
Enable ethical metrics and receive alerts whenever your dappnode is
down without losing your privacy.{" "}
<a href={docsUrl.ethicalMetricsOverview}>Learn more</a>
<p className="description-text">
<span className="highlight">Enable ethical metrics</span> and
receive alerts whenever your dappnode is down without compromising
your privacy.
<span className="note">
{" "}
Note: Ethical Metrics requires the Dappnode Monitoring Service
(DMS) as a dependency.
</span>{" "}
<a href={docsUrl.ethicalMetricsOverview} className="learn-more">
Learn more
</a>
</p>
</div>
</div>

<p className="instructions">
<strong>Telegram notifications are available!</strong> Enter your{" "}
<strong>Telegram Channel ID</strong> to receive reliable alerts
promptly.
</p>
<em className="advice">
<strong>Advice: </strong> We highly recommend using the Telegram channel
option (or both) rather than relying only on email notifications. Email
notifications may be categorized as spam, potentially causing you to
miss important notifications!
</em>
{!ethicalMetricsOn && (
<span
style={{
fontStyle: "italic",
fontSize: "14px",
color: "var(--dappnode-strong-main-color)"
}}
>
You must provide a Telegram channel ID or an email to enable ethical
metrics notifications
</span>
)}
<span>Ethical metrics notifications by telegram channel</span>
<div>
<Input
prepend="Telegram"
value={tgChannelId}
onValueChange={setTgChannelId}
isInvalid={tgChannelIdError}
required={true}
placeholder="-100XXXXXXXXXX"
/>
<Accordion defaultActiveKey={tgAccordionOpen ? "0" : ""}>
<div className="accordion-modal-wrapper">
<Accordion.Toggle
eventKey="0"
onClick={() => setTgAccordionOpen(!tgAccordionOpen)}
className="accordion-modal"
>
<div className="header">
<BsInfoCircleFill
className="links-icon"
style={{ fontSize: "14px" }}
/>
How can I get a Telegram channel Id?{" "}
{tgAccordionOpen ? <IoIosArrowUp /> : <IoIosArrowDown />}{" "}
</div>
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<div>
<ol>
<li>
Open{" "}
<a
href="https://web.telegram.org/a/"
target="_blank"
rel="noopener noreferrer"
>
Telegram web
</a>
.
<ul>
<li>
Ensure the URL ends with <span>/a/</span>. If not,
manually add <span>/a/</span> after{" "}
<span>https://web.telegram.org</span>.{" "}
</li>
</ul>
</li>
<li>Create a private channel.</li>
<li>
Add <span>@ethicalMetricsAlerts_bot</span> as an
administrator in the channel.
</li>
<li>
Go to your channel and copy the 13-digit ID from the URL.
<ul>
<li>
The channel ID always starts with <span>-100</span>.
Ensure to include the <span>-</span> when coping it.
</li>
</ul>
</li>

<li>
Paste the ID into the Telegram Channel ID field and enable
Ethical Metrics to receive notifications.
</li>
</ol>
</div>
</Accordion.Collapse>
</div>
</Accordion>
</div>
{tgChannelIdError && (
<span style={{ fontSize: "12px", color: "red" }}>
Telegram channel ID format is incorrect
</span>
)}

<span>Ethical metrics notifications by email</span>
<Input
prepend="Email"
value={mail}
Expand All @@ -57,19 +221,64 @@ export default function EnableEthicalMetrics({
required={true}
placeholder="example@email.com"
/>
{mailError && (
<span style={{ fontSize: "12px", color: "red" }}>
Email format is incorrect
</span>
)}

{/* This top div prevents the card from stretching vertically */}
<div>
<SwitchBig
disabled={mailError}
checked={ethicalMetricsOn}
onChange={setEthicalMetricsOn}
label="Enable system notifications"
id="enable-ethical-metrics"
/>
{ethicalMetricsOn ? (
// Render the "Update" button if ethical metrics are enabled
<div className="update-button">
<Button
type="submit"
onClick={async () => {
setValidationMessage("");
await enableEthicalMetricsSync();
}}
variant="dappnode"
disabled={
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you try to simplify this condition?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks a bit complex

// No input provided or both inputs have errors
(tgChannelId === "" && mail === "") ||
(tgChannelIdError && mailError) ||
// Only tgChannelId has error or only mail has error
(tgChannelIdError && mail === "") ||
(tgChannelId === "" && mailError) ||
// No changes in mail or tgChannelId
(mail === ethicalMetricsConfig.data?.mail &&
(tgChannelId === "" ||
tgChannelId === ethicalMetricsConfig.data?.tgChannelId ||
tgChannelIdError)) ||
// Asynchronous operation in progress
validationMessage !== ""
}
>
Update
</Button>
</div>
) : (
<SwitchBig
disabled={
(tgChannelId === "" && mail === "") ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

(tgChannelIdError && mailError) ||
(tgChannelIdError && mail === "") ||
(tgChannelId === "" && mailError)
}
checked={ethicalMetricsOn}
onChange={toggleEthicalSwitch}
label=""
id="enable-ethical-metrics"
/>
)}
</div>

<BottomButtons onBack={onBack} onNext={onSetEnabeEthicalMetrics} />
</>
<BottomButtons onBack={onBack} onNext={() => onNext()} />

{validationMessage && (
<p className="validation-message">{validationMessage}</p>
)}
</div>
);
}
Loading
Loading