Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions client/src/Features/UI/uiSlice.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ const uiSlice = createSlice({
state.showURL = action.payload;
},
setGreeting(state, action) {
if (!state.greeting) {
state.greeting = { index: 0, lastUpdate: null };
}
state.greeting.index = action.payload.index;
state.greeting.lastUpdate = action.payload.lastUpdate;
},
Expand Down
18 changes: 17 additions & 1 deletion client/src/Hooks/useNotifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { createToast } from "../Utils/toastUtils";
import { networkService } from "../main";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { NOTIFICATION_TYPES } from "../Pages/Notifications/utils";
import {
NOTIFICATION_TYPES,
NTFY_AUTH_METHODS,
NTFY_PRIORITIES,
} from "../Pages/Notifications/utils";

const useCreateNotification = () => {
const navigate = useNavigate();
Expand Down Expand Up @@ -103,6 +107,18 @@ const useGetNotificationById = (id, setNotification) => {
address: notification?.address,
notificationName: notification?.notificationName,
type: NOTIFICATION_TYPES.find((type) => type.value === notification?.type)?._id,
// ntfy-specific fields
ntfyAuthMethod:
NTFY_AUTH_METHODS.find(
(method) => method.value === notification?.ntfyAuthMethod
)?._id || NTFY_AUTH_METHODS[0]._id,
ntfyUsername: notification?.ntfyUsername || "",
ntfyPassword: notification?.ntfyPassword || "",
ntfyBearerToken: notification?.ntfyBearerToken || "",
ntfyPriority:
NTFY_PRIORITIES.find(
(priority) => priority.value === notification?.ntfyPriority
)?._id || NTFY_PRIORITIES[2]._id,
};

setNotification(notificationData);
Expand Down
103 changes: 103 additions & 0 deletions client/src/Pages/Notifications/create/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import {
DESCRIPTION_MAP,
LABEL_MAP,
PLACEHOLDER_MAP,
NTFY_AUTH_METHODS,
NTFY_PRIORITIES,
} from "../utils";

// Setup
Expand Down Expand Up @@ -57,6 +59,12 @@ const CreateNotifications = () => {
notificationName: "",
address: "",
type: NOTIFICATION_TYPES[0]._id,
// ntfy-specific fields
ntfyAuthMethod: NTFY_AUTH_METHODS[0]._id, // "None" option _id
ntfyUsername: "",
ntfyPassword: "",
ntfyBearerToken: "",
ntfyPriority: NTFY_PRIORITIES[2]._id, // "Default" option _id (3)
});
const [errors, setErrors] = useState({});
const { t } = useTranslation();
Expand All @@ -69,6 +77,16 @@ const CreateNotifications = () => {
return NOTIFICATION_TYPES.find((type) => type._id === typeId)?.value || "email";
};

const getNtfyAuthMethodValue = (authMethodId) => {
return (
NTFY_AUTH_METHODS.find((method) => method._id === authMethodId)?.value || "none"
);
};

const getNtfyPriorityValue = (priorityId) => {
return NTFY_PRIORITIES.find((priority) => priority._id === priorityId)?.value || 3;
};

const extractError = (error, field) =>
error?.details.find((d) => d.path.includes(field))?.message;

Comment on lines 90 to 92
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix optional chaining to avoid runtime crash when no errors.

error?.details.find will throw because details can be undefined. Chain details too.

Apply this diff:

-const extractError = (error, field) =>
-  error?.details.find((d) => d.path.includes(field))?.message;
+const extractError = (error, field) =>
+  error?.details?.find((d) => d.path?.includes(field))?.message;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const extractError = (error, field) =>
error?.details.find((d) => d.path.includes(field))?.message;
const extractError = (error, field) =>
error?.details?.find((d) => d.path?.includes(field))?.message;
🤖 Prompt for AI Agents
In client/src/Pages/Notifications/create/index.jsx around lines 88 to 90, the
helper uses error?.details.find(...) which will throw if details is undefined;
change the optional chaining to access details as well (e.g.,
error?.details?.find(...)) so the call short-circuits when details is missing
and preserve the existing optional chaining on the message.

Expand All @@ -78,6 +96,9 @@ const CreateNotifications = () => {
const form = {
...notification,
type: getNotificationTypeValue(notification.type),
// Convert ntfy dropdown IDs to actual values
ntfyAuthMethod: getNtfyAuthMethodValue(notification.ntfyAuthMethod),
ntfyPriority: getNtfyPriorityValue(notification.ntfyPriority),
};

let error = null;
Expand Down Expand Up @@ -107,6 +128,9 @@ const CreateNotifications = () => {
let newNotification = {
...rawNotification,
type: getNotificationTypeValue(rawNotification.type),
// Convert ntfy dropdown IDs to actual values for validation
ntfyAuthMethod: getNtfyAuthMethodValue(rawNotification.ntfyAuthMethod),
ntfyPriority: getNtfyPriorityValue(rawNotification.ntfyPriority),
};

const { error } = notificationValidation.validate(newNotification, {
Expand All @@ -117,6 +141,12 @@ const CreateNotifications = () => {
if (name === "type") {
validationError["type"] = extractError(error, "type");
validationError["address"] = extractError(error, "address");
} else if (name === "ntfyAuthMethod") {
// When auth method changes, update all ntfy field errors
validationError["ntfyAuthMethod"] = extractError(error, "ntfyAuthMethod");
validationError["ntfyUsername"] = extractError(error, "ntfyUsername");
validationError["ntfyPassword"] = extractError(error, "ntfyPassword");
validationError["ntfyBearerToken"] = extractError(error, "ntfyBearerToken");
} else {
validationError[name] = extractError(error, name);
}
Expand All @@ -129,6 +159,9 @@ const CreateNotifications = () => {
const form = {
...notification,
type: getNotificationTypeValue(notification.type),
// Convert ntfy dropdown IDs to actual values
ntfyAuthMethod: getNtfyAuthMethodValue(notification.ntfyAuthMethod),
ntfyPriority: getNtfyPriorityValue(notification.ntfyPriority),
};

let error = null;
Expand Down Expand Up @@ -232,6 +265,76 @@ const CreateNotifications = () => {
error={Boolean(errors.address)}
helperText={errors["address"]}
/>

{/* ntfy-specific fields */}
{type === "ntfy" && (
<>
<Select
items={NTFY_AUTH_METHODS}
label={t("createNotifications.ntfySettings.authMethodLabel")}
name="ntfyAuthMethod"
value={notification.ntfyAuthMethod}
onChange={onChange}
error={Boolean(errors.ntfyAuthMethod)}
helperText={errors["ntfyAuthMethod"]}
/>

{getNtfyAuthMethodValue(notification.ntfyAuthMethod) ===
"username_password" && (
<>
<TextInput
label={t("createNotifications.ntfySettings.usernameLabel")}
name="ntfyUsername"
placeholder={t(
"createNotifications.ntfySettings.usernamePlaceholder"
)}
value={notification.ntfyUsername}
onChange={onChange}
error={Boolean(errors.ntfyUsername)}
helperText={errors["ntfyUsername"]}
/>
<TextInput
type="password"
label={t("createNotifications.ntfySettings.passwordLabel")}
name="ntfyPassword"
placeholder={t(
"createNotifications.ntfySettings.passwordPlaceholder"
)}
value={notification.ntfyPassword}
onChange={onChange}
error={Boolean(errors.ntfyPassword)}
helperText={errors["ntfyPassword"]}
/>
</>
)}

{getNtfyAuthMethodValue(notification.ntfyAuthMethod) ===
"bearer_token" && (
<TextInput
type="password"
label={t("createNotifications.ntfySettings.bearerTokenLabel")}
name="ntfyBearerToken"
placeholder={t(
"createNotifications.ntfySettings.bearerTokenPlaceholder"
)}
value={notification.ntfyBearerToken}
onChange={onChange}
error={Boolean(errors.ntfyBearerToken)}
helperText={errors["ntfyBearerToken"]}
/>
)}

<Select
items={NTFY_PRIORITIES}
label={t("createNotifications.ntfySettings.priorityLabel")}
name="ntfyPriority"
value={notification.ntfyPriority}
onChange={onChange}
error={Boolean(errors.ntfyPriority)}
helperText={errors["ntfyPriority"]}
/>
</>
)}
</Stack>
</ConfigBox>

Expand Down
20 changes: 20 additions & 0 deletions client/src/Pages/Notifications/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const NOTIFICATION_TYPES = [
{ _id: 3, name: "PagerDuty", value: "pager_duty" },
{ _id: 4, name: "Webhook", value: "webhook" },
{ _id: 5, name: "Discord", value: "discord" },
{ _id: 6, name: "ntfy", value: "ntfy" },
];

export const TITLE_MAP = {
Expand All @@ -12,6 +13,7 @@ export const TITLE_MAP = {
pager_duty: "createNotifications.pagerdutySettings.title",
webhook: "createNotifications.webhookSettings.title",
discord: "createNotifications.discordSettings.title",
ntfy: "createNotifications.ntfySettings.title",
};

export const DESCRIPTION_MAP = {
Expand All @@ -20,6 +22,7 @@ export const DESCRIPTION_MAP = {
pager_duty: "createNotifications.pagerdutySettings.description",
webhook: "createNotifications.webhookSettings.description",
discord: "createNotifications.discordSettings.description",
ntfy: "createNotifications.ntfySettings.description",
};

export const LABEL_MAP = {
Expand All @@ -28,6 +31,7 @@ export const LABEL_MAP = {
pager_duty: "createNotifications.pagerdutySettings.integrationKeyLabel",
webhook: "createNotifications.webhookSettings.webhookLabel",
discord: "createNotifications.discordSettings.webhookLabel",
ntfy: "createNotifications.ntfySettings.urlLabel",
};

export const PLACEHOLDER_MAP = {
Expand All @@ -36,4 +40,20 @@ export const PLACEHOLDER_MAP = {
pager_duty: "createNotifications.pagerdutySettings.integrationKeyPlaceholder",
webhook: "createNotifications.webhookSettings.webhookPlaceholder",
discord: "createNotifications.discordSettings.webhookPlaceholder",
ntfy: "createNotifications.ntfySettings.urlPlaceholder",
};

// ntfy-specific constants
export const NTFY_AUTH_METHODS = [
{ _id: 1, name: "None", value: "none" },
{ _id: 2, name: "Username/Password", value: "username_password" },
{ _id: 3, name: "Bearer Token", value: "bearer_token" },
];

export const NTFY_PRIORITIES = [
{ _id: 1, name: "Min", value: 1 },
{ _id: 2, name: "Low", value: 2 },
{ _id: 3, name: "Default", value: 3 },
{ _id: 4, name: "High", value: 4 },
{ _id: 5, name: "Urgent", value: 5 },
];
9 changes: 5 additions & 4 deletions client/src/Utils/greeting.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ const Greeting = ({ type = "" }) => {
const theme = useTheme();
const dispatch = useDispatch();
const { t } = useTranslation();
const { firstName } = useSelector((state) => state.auth.user);
const index = useSelector((state) => state.ui.greeting.index);
const lastUpdate = useSelector((state) => state.ui.greeting.lastUpdate);
const { firstName } = useSelector((state) => state.auth.user || {});
const index = useSelector((state) => state.ui.greeting?.index ?? 0);
const lastUpdate = useSelector((state) => state.ui.greeting?.lastUpdate ?? null);

const now = new Date();
const hour = now.getHours();
Expand All @@ -153,7 +153,8 @@ const Greeting = ({ type = "" }) => {

let greetingArray =
hour < 6 ? early : hour < 12 ? morning : hour < 18 ? afternoon : evening;
const { prepend, append, emoji } = greetingArray[index];
const safeIndex = index >= 0 && index < greetingArray.length ? index : 0;
const { prepend, append, emoji } = greetingArray[safeIndex];

return (
<Box>
Expand Down
71 changes: 69 additions & 2 deletions client/src/Validation/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,12 +446,13 @@ const notificationValidation = joi.object({

type: joi
.string()
.valid("email", "webhook", "slack", "discord", "pager_duty")
.valid("email", "webhook", "slack", "discord", "pager_duty", "ntfy")
.required()
.messages({
"string.empty": "Notification type is required",
"any.required": "Notification type is required",
"any.only": "Notification type must be email, webhook, or pager_duty",
"any.only":
"Notification type must be email, webhook, slack, discord, pager_duty, or ntfy",
}),

address: joi.when("type", {
Expand Down Expand Up @@ -483,8 +484,74 @@ const notificationValidation = joi.object({
"string.uri": "Please enter a valid Webhook URL",
}),
},
{
is: "ntfy",
then: joi.string().uri().required().messages({
"string.empty": "ntfy URL cannot be empty",
"any.required": "ntfy URL is required",
"string.uri": "Please enter a valid ntfy URL",
}),
},
],
}),

// ntfy-specific fields
ntfyAuthMethod: joi.when("type", {
is: "ntfy",
then: joi.string().valid("none", "username_password", "bearer_token").default("none"),
otherwise: joi.forbidden(),
}),

ntfyUsername: joi.when("type", {
is: "ntfy",
then: joi.when("ntfyAuthMethod", {
is: "username_password",
then: joi.string().required().messages({
"string.empty":
"Username cannot be empty when using username/password authentication",
"any.required": "Username is required for username/password authentication",
}),
otherwise: joi.string().optional().allow(""),
}),
otherwise: joi.forbidden(),
}),

ntfyPassword: joi.when("type", {
is: "ntfy",
then: joi.when("ntfyAuthMethod", {
is: "username_password",
then: joi.string().required().messages({
"string.empty":
"Password cannot be empty when using username/password authentication",
"any.required": "Password is required for username/password authentication",
}),
otherwise: joi.string().optional().allow(""),
}),
Comment on lines +523 to +529
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Trim password.

Same rationale as username.

-          then: joi.string().required().messages({
+          /* biome-ignore lint/suspicious/noThenProperty: Joi uses 'then'. */
+          then: joi.string().trim().required().messages({
             "string.empty":
               "Password cannot be empty when using username/password authentication",
             "any.required": "Password is required for username/password authentication",
           }),
-          otherwise: joi.string().optional().allow(""),
+          otherwise: joi.string().trim().optional().allow(""),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
then: joi.string().required().messages({
"string.empty":
"Password cannot be empty when using username/password authentication",
"any.required": "Password is required for username/password authentication",
}),
otherwise: joi.string().optional().allow(""),
}),
/* biome-ignore lint/suspicious/noThenProperty: Joi uses 'then'. */
then: joi.string().trim().required().messages({
"string.empty":
"Password cannot be empty when using username/password authentication",
"any.required": "Password is required for username/password authentication",
}),
otherwise: joi.string().trim().optional().allow(""),
}),
🧰 Tools
🪛 Biome (2.1.2)

[error] 523-523: Do not add then to an object.

(lint/suspicious/noThenProperty)

🤖 Prompt for AI Agents
In client/src/Validation/validation.js around lines 523 to 529, the password
schema doesn't trim input like the username does; update the Joi schema to call
.trim() on both the required and optional branches so leading/trailing
whitespace is removed (i.e., use joi.string().trim().required() in the then
branch and joi.string().trim().optional().allow("") in the otherwise branch).

otherwise: joi.forbidden(),
}),

ntfyBearerToken: joi.when("type", {
is: "ntfy",
then: joi.when("ntfyAuthMethod", {
is: "bearer_token",
then: joi.string().required().messages({
"string.empty":
"Bearer token cannot be empty when using bearer token authentication",
"any.required": "Bearer token is required for bearer token authentication",
}),
otherwise: joi.string().optional().allow(""),
}),
otherwise: joi.forbidden(),
}),

ntfyPriority: joi.when("type", {
is: "ntfy",
then: joi.number().min(1).max(5).default(3).messages({
"number.min": "Priority must be between 1 and 5",
"number.max": "Priority must be between 1 and 5",
}),
otherwise: joi.forbidden(),
}),
Comment on lines +547 to +554
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enforce integer priority 1–5.

Avoids floats like 3.14.

-    then: joi.number().min(1).max(5).default(3).messages({
+    then: joi.number().integer().min(1).max(5).default(3).messages({
+      "number.integer": "Priority must be an integer between 1 and 5",
       "number.min": "Priority must be between 1 and 5",
       "number.max": "Priority must be between 1 and 5",
     }),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ntfyPriority: joi.when("type", {
is: "ntfy",
then: joi.number().min(1).max(5).default(3).messages({
"number.min": "Priority must be between 1 and 5",
"number.max": "Priority must be between 1 and 5",
}),
otherwise: joi.forbidden(),
}),
ntfyPriority: joi.when("type", {
is: "ntfy",
then: joi.number().integer().min(1).max(5).default(3).messages({
"number.integer": "Priority must be an integer between 1 and 5",
"number.min": "Priority must be between 1 and 5",
"number.max": "Priority must be between 1 and 5",
}),
otherwise: joi.forbidden(),
}),
🧰 Tools
🪛 Biome (2.1.2)

[error] 545-545: Do not add then to an object.

(lint/suspicious/noThenProperty)

🤖 Prompt for AI Agents
In client/src/Validation/validation.js around lines 543 to 550, the ntfyPriority
schema allows non-integer numbers (e.g., 3.14); update the schema to require
integers by adding .integer() to the joi.number() chain and adjust validation
messages to include an integer-specific message (e.g., "number.integer":
"Priority must be an integer between 1 and 5") while keeping the min(1), max(5)
and default(3); ensure otherwise remains joi.forbidden().

Comment on lines +487 to +554
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Silence Biome’s false-positive on Joi’s then keys.

Biome’s noThenProperty trips on Joi condition objects; add inline ignores (as shown) or disable this rule for this file in config. Otherwise CI will fail despite valid Joi.

Happy to open a quick PR to add targeted /* biome-ignore lint/suspicious/noThenProperty */ comments or tweak .biomerc config.

🧰 Tools
🪛 Biome (2.1.2)

[error] 489-489: Do not add then to an object.

(lint/suspicious/noThenProperty)


[error] 501-501: Do not add then to an object.

(lint/suspicious/noThenProperty)


[error] 507-507: Do not add then to an object.

(lint/suspicious/noThenProperty)


[error] 509-509: Do not add then to an object.

(lint/suspicious/noThenProperty)


[error] 521-521: Do not add then to an object.

(lint/suspicious/noThenProperty)


[error] 523-523: Do not add then to an object.

(lint/suspicious/noThenProperty)


[error] 535-535: Do not add then to an object.

(lint/suspicious/noThenProperty)


[error] 537-537: Do not add then to an object.

(lint/suspicious/noThenProperty)


[error] 549-549: Do not add then to an object.

(lint/suspicious/noThenProperty)

🤖 Prompt for AI Agents
In client/src/Validation/validation.js around lines 487 to 554, Biome's
false-positive rule lint/suspicious/noThenProperty flags Joi conditional
objects' "then" keys; fix by adding targeted inline Biome ignore comments before
the affected Joi.when expressions (e.g. place /* biome-ignore
lint/suspicious/noThenProperty */ immediately above each Joi.when that uses a
then key) or, if preferred, add a single file-scoped disable (/* biome-disable
lint/suspicious/noThenProperty */ at the top of this file) so CI stops failing
while preserving the valid Joi schema code.

});

const editUserValidation = joi.object({
Expand Down
14 changes: 14 additions & 0 deletions client/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,20 @@
"webhookLabel": "Webhook URL",
"webhookPlaceholder": "https://your-server.com/webhook"
},
"ntfySettings": {
"title": "ntfy",
"description": "Send push notifications via ntfy (self-hosted or ntfy.sh)",
"urlLabel": "ntfy Topic URL",
"urlPlaceholder": "https://ntfy.sh/my-topic",
"authMethodLabel": "Authentication Method",
"usernameLabel": "Username",
"usernamePlaceholder": "Enter username",
"passwordLabel": "Password",
"passwordPlaceholder": "Enter password",
"bearerTokenLabel": "Bearer Token",
"bearerTokenPlaceholder": "Enter bearer token",
"priorityLabel": "Priority"
},
Comment on lines +693 to +706
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add i18n for ntfy option labels to avoid hard-coded UI text

NTFY auth-method and priority options are hard-coded in utils.js. Provide localized strings here so the UI can use i18n consistently.

 		"ntfySettings": {
 			"title": "ntfy",
 			"description": "Send push notifications via ntfy (self-hosted or ntfy.sh)",
 			"urlLabel": "ntfy Topic URL",
 			"urlPlaceholder": "https://ntfy.sh/my-topic",
 			"authMethodLabel": "Authentication Method",
+			"authMethodOptions": {
+				"none": "None",
+				"username_password": "Username/Password",
+				"bearer_token": "Bearer Token"
+			},
 			"usernameLabel": "Username",
 			"usernamePlaceholder": "Enter username",
 			"passwordLabel": "Password",
 			"passwordPlaceholder": "Enter password",
 			"bearerTokenLabel": "Bearer Token",
 			"bearerTokenPlaceholder": "Enter bearer token",
-			"priorityLabel": "Priority"
+			"priorityLabel": "Priority",
+			"priorityOptions": {
+				"1": "Min",
+				"2": "Low",
+				"3": "Default",
+				"4": "High",
+				"5": "Urgent"
+			}
 		},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"ntfySettings": {
"title": "ntfy",
"description": "Send push notifications via ntfy (self-hosted or ntfy.sh)",
"urlLabel": "ntfy Topic URL",
"urlPlaceholder": "https://ntfy.sh/my-topic",
"authMethodLabel": "Authentication Method",
"usernameLabel": "Username",
"usernamePlaceholder": "Enter username",
"passwordLabel": "Password",
"passwordPlaceholder": "Enter password",
"bearerTokenLabel": "Bearer Token",
"bearerTokenPlaceholder": "Enter bearer token",
"priorityLabel": "Priority"
},
"ntfySettings": {
"title": "ntfy",
"description": "Send push notifications via ntfy (self-hosted or ntfy.sh)",
"urlLabel": "ntfy Topic URL",
"urlPlaceholder": "https://ntfy.sh/my-topic",
"authMethodLabel": "Authentication Method",
"authMethodOptions": {
"none": "None",
"username_password": "Username/Password",
"bearer_token": "Bearer Token"
},
"usernameLabel": "Username",
"usernamePlaceholder": "Enter username",
"passwordLabel": "Password",
"passwordPlaceholder": "Enter password",
"bearerTokenLabel": "Bearer Token",
"bearerTokenPlaceholder": "Enter bearer token",
"priorityLabel": "Priority",
"priorityOptions": {
"1": "Min",
"2": "Low",
"3": "Default",
"4": "High",
"5": "Urgent"
}
},
🤖 Prompt for AI Agents
client/src/locales/en.json around lines 693 to 706, the ntfy UI currently uses
hard-coded option labels from utils.js; add localized string entries for the
auth-method options and priority options so the UI can use i18n consistently.
Add keys under "ntfySettings" like "authMethodOptions": { "none": "None",
"basic": "Basic", "bearer": "Bearer" } and "priorityOptions": { "min": "Min",
"low": "Low", "default": "Default", "high": "High", "urgent": "Urgent" } (or
match the exact option identifiers used in utils.js) so components can reference
these i18n keys instead of hard-coded text.

"testNotification": "Test notification",
"dialogDeleteTitle": "Are you sure you want to delete this notification?",
"dialogDeleteConfirm": "Delete"
Expand Down
Loading