Merge branch 'main' into web-improvements

This commit is contained in:
binwiederhier 2023-05-24 22:28:53 -04:00
commit 2697600111
13 changed files with 256 additions and 379 deletions

View File

@ -1222,8 +1222,13 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release
### ntfy server v2.6.0 (UNRELEASED)
**Bug fixes + maintenance:**
**Bug fixes:**
* Support encoding any header as RFC 2047 ([#737](https://github.com/binwiederhier/ntfy/issues/737), thanks to [@cfouche3005](https://github.com/cfouche3005) for reporting)
**Maintenance:**
* Improved GitHub Actions flow ([#745](https://github.com/binwiederhier/ntfy/pull/745), thanks to [@nimbleghost](https://github.com/nimbleghost))
* Web: Add JS formatter "prettier" ([#746](https://github.com/binwiederhier/ntfy/pull/746), thanks to [@nimbleghost](https://github.com/nimbleghost))
* Web: Add eslint with eslint-config-airbnb ([#748](https://github.com/binwiederhier/ntfy/pull/748), thanks to [@nimbleghost](https://github.com/nimbleghost))
* Web: Switch to Vite ([#749](https://github.com/binwiederhier/ntfy/pull/749), thanks to [@nimbleghost](https://github.com/nimbleghost))

View File

@ -20,6 +20,12 @@
"react/destructuring-assignment": "off",
"react/jsx-no-useless-fragment": "off",
"react/jsx-props-no-spreading": "off",
"react/jsx-no-duplicate-props": [
"error",
{
"ignoreCase": false // For <TextField>'s [iI]nputProps
}
],
"react/function-component-definition": [
"error",
{

500
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,8 @@
"lint": "eslint --report-unused-disable-directives --ext .js,.jsx ./src/"
},
"dependencies": {
"@emotion/react": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.4.2",
"@mui/material": "latest",
"dexie": "^3.2.1",

View File

@ -352,5 +352,24 @@
"account_upgrade_dialog_interval_yearly_discount_save_up_to": "économisez jusqu'à {{discount}}%",
"account_upgrade_dialog_tier_price_per_month": "mois",
"account_upgrade_dialog_tier_price_billed_yearly": "{{price}} prélevé annuellement. Économisez {{save}}.",
"account_upgrade_dialog_billing_contact_email": "Pour des questions concernant la facturation, merci de nous <Link>contacter</Link> directement."
"account_upgrade_dialog_billing_contact_email": "Pour des questions concernant la facturation, merci de nous <Link>contacter</Link> directement.",
"publish_dialog_call_label": "Appel téléphonique",
"account_basics_phone_numbers_title": "Numéros de téléphone",
"account_basics_phone_numbers_dialog_description": "Pour utiliser la fonctionnalité de notification par appels, vous devez ajouter et vérifier au moins un numéro de téléphone. La vérification peut se faire par SMS ou appel téléphonique.",
"account_basics_phone_numbers_description": "Pour des notifications par appel téléphoniques",
"account_basics_phone_numbers_no_phone_numbers_yet": "Pas encore de numéros de téléphone",
"account_basics_phone_numbers_copied_to_clipboard": "Numéro de téléphone copié dans le presse-papier",
"account_basics_phone_numbers_dialog_title": "Ajouter un numéro de téléphone",
"account_basics_phone_numbers_dialog_number_label": "Numéro de téléphone",
"account_basics_phone_numbers_dialog_number_placeholder": "Ex : +33701020304",
"account_basics_phone_numbers_dialog_verify_button_sms": "Envoyer un SMS",
"account_basics_phone_numbers_dialog_verify_button_call": "Appelez moi",
"account_basics_phone_numbers_dialog_code_label": "Code de vérification",
"account_basics_phone_numbers_dialog_code_placeholder": "Ex : 123456",
"account_basics_phone_numbers_dialog_check_verification_button": "Code de confirmarion",
"account_basics_phone_numbers_dialog_channel_sms": "SMS",
"account_basics_phone_numbers_dialog_channel_call": "Appel",
"account_usage_calls_none": "Aucun appels téléphoniques ne peut être fait avec ce compte",
"publish_dialog_call_reset": "Supprimer les appels téléphoniques",
"publish_dialog_chip_call_label": "Appel téléphonique"
}

View File

@ -295,5 +295,62 @@
"account_usage_messages_title": "Опубліковані повідомлення",
"account_usage_emails_title": "Надіслані електронні листи",
"account_usage_reservations_title": "Зарезервовані теми",
"account_usage_reservations_none": "Для цього облікового запису немає зарезервованих тем"
"account_usage_reservations_none": "Для цього облікового запису немає зарезервованих тем",
"account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} на файл",
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} загальне сховище",
"account_upgrade_dialog_tier_current_label": "Поточний",
"account_upgrade_dialog_tier_selected_label": "Вибране",
"account_upgrade_dialog_cancel_warning": "Це <strong> скасує вашу підписку</strong> і знизить версію вашого облікового запису {{date}}. У цю дату резервування тем, а також повідомлення, кешовані на сервері <strong>, буде видалено</strong>.",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} зарезервовані теми",
"account_upgrade_dialog_tier_features_no_reservations": "Немає зарезервованих тем",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} повідомлень в день",
"account_upgrade_dialog_tier_features_emails_one": "{{emails}} електронний лист в день",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} електронних листів в день",
"account_upgrade_dialog_tier_features_calls_one": "{{calls}} телефонний дзвінок в день",
"account_upgrade_dialog_tier_features_calls_other": "{{дзвінки}} телефонних дзвінків в день",
"account_upgrade_dialog_tier_features_no_calls": "Без телефонних дзвінків",
"account_upgrade_dialog_tier_price_per_month": "місяць",
"account_upgrade_dialog_tier_price_billed_monthly": "{{price}} на рік. Рахунок виставляється щомісяця.",
"account_upgrade_dialog_tier_price_billed_yearly": "{{price}} виставляється щорічно. Збережіть {{save}}.",
"account_upgrade_dialog_billing_contact_email": "Якщо у вас виникли запитання щодо оплати, <Link>зв’яжіться з нами</Link> безпосередньо.",
"account_upgrade_dialog_billing_contact_website": "Якщо у вас виникли запитання щодо оплати, відвідайте наш <Link>веб-сайт</Link>.",
"account_upgrade_dialog_button_cancel_subscription": "Скасувати підписку",
"account_upgrade_dialog_button_update_subscription": "Оновити підписку",
"account_tokens_title": "Токени доступу",
"account_tokens_table_expires_header": "Термін дії закінчується",
"account_tokens_description": "Використовуйте токени доступу при публікації та підписці через ntfy API, щоб не надсилати свої облікові дані. Ознайомтеся з <Link>документацією</Link>, щоб дізнатися більше.",
"account_tokens_table_token_header": "Токен",
"account_tokens_table_never_expires": "Ніколи не закінчується",
"account_tokens_table_label_header": "Мітка",
"account_tokens_table_current_session": "Поточний сеанс браузера",
"account_tokens_table_last_access_header": "Останній доступ",
"account_tokens_table_copied_to_clipboard": "Токен доступу скопійовано",
"account_tokens_table_cannot_delete_or_edit": "Неможливо редагувати або видалити токен поточного сеансу",
"account_tokens_table_create_token_button": "Створити токен доступу",
"account_tokens_table_last_origin_tooltip": "З IP-адреси {{ip}} натисніть для пошуку",
"account_tokens_dialog_title_create": "Створити токен доступу",
"account_tokens_dialog_button_cancel": "Скасувати",
"account_tokens_dialog_title_edit": "Редагувати токен доступу",
"account_tokens_dialog_title_delete": "Видалити токен доступу",
"account_tokens_dialog_label": "Мітка, наприклад, сповіщення Radarr",
"account_tokens_dialog_button_create": "Створити токен",
"account_tokens_dialog_button_update": "Оновити токен",
"account_tokens_dialog_expires_label": "Термін дії токену доступу закінчується через",
"account_tokens_dialog_expires_x_hours": "Термін дії токена закінчується через {{hours}} годин",
"account_tokens_dialog_expires_x_days": "Термін дії токена закінчується через {{days}} днів",
"account_tokens_delete_dialog_description": "Перш ніж видалити токен доступу, переконайтеся, що жодна програма або скрипт не використовує його. <strong>Ця дія не може бути скасована</strong>.",
"prefs_users_description_no_sync": "Користувачі та паролі не синхронізуються з вашим акаунтом.",
"prefs_users_table_cannot_delete_or_edit": "Неможливо видалити або відредагувати користувача, який увійшов у систему",
"account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} зарезервована тема",
"account_upgrade_dialog_tier_features_messages_one": "{{messages}} повідомлення в день",
"account_tokens_dialog_expires_unchanged": "Залишити термін придатності без змін",
"account_tokens_dialog_expires_never": "Термін дії токена ніколи не закінчується",
"account_tokens_delete_dialog_title": "Видалити токен доступу",
"account_tokens_delete_dialog_submit_button": "Видалити токен назавжди",
"account_upgrade_dialog_proration_info": "<strong>Пропорція</strong>: При переході з одного тарифного плану на інший різниця в ціні буде <strong>списана негайно</strong>. При переході на нижчий рівень залишок коштів буде використано для оплати майбутніх розрахункових періодів.",
"account_upgrade_dialog_reservations_warning_one": "Обраний рівень дозволяє менше зарезервованих тем, ніж ваш поточний рівень. Перш ніж змінити свій рівень, <strong>будь ласка, видаліть принаймні одне резервування</strong>. Ви можете видалити резервування в <Link>Налаштуваннях</Link>.",
"account_upgrade_dialog_reservations_warning_other": "Обраний рівень дозволяє менше зарезервованих тем, ніж ваш поточний рівень. Перш ніж змінити свій рівень, <strong>будь ласка, видаліть принаймні {{count}} резервувань</strong>. Ви можете видалити резервування в <Link>Налаштуваннях</Link>.",
"account_upgrade_dialog_button_cancel": "Скасувати",
"account_upgrade_dialog_button_redirect_signup": "Зареєструватися зараз",
"account_upgrade_dialog_button_pay_now": "Оплатити зараз і підписатися"
}

View File

@ -994,6 +994,7 @@ const TokenDialog = (props) => {
const TokenDeleteDialog = (props) => {
const { t } = useTranslation();
const [error, setError] = useState("");
const handleSubmit = async () => {
try {
@ -1003,6 +1004,8 @@ const TokenDeleteDialog = (props) => {
console.log(`[Account] Error deleting token`, e);
if (e instanceof UnauthorizedError) {
session.resetAndRedirect(routes.login);
} else {
setError(e.message);
}
}
};
@ -1015,7 +1018,7 @@ const TokenDeleteDialog = (props) => {
<Trans i18nKey="account_tokens_delete_dialog_description" />
</DialogContentText>
</DialogContent>
<DialogFooter status>
<DialogFooter status={error}>
<Button onClick={props.onClose}>{t("common_cancel")}</Button>
<Button onClick={handleSubmit} color="error">
{t("account_tokens_delete_dialog_submit_button")}

View File

@ -27,14 +27,13 @@ export const AccountContext = createContext(null);
const App = () => {
const [account, setAccount] = useState(null);
const contextValue = useMemo(() => ({ account, setAccount }), [account, setAccount]);
const accountMemo = useMemo(() => ({ account, setAccount }), [account, setAccount]);
return (
<Suspense fallback={<Loader />}>
<BrowserRouter>
<ThemeProvider theme={theme}>
<AccountContext.Provider value={contextValue}>
<AccountContext.Provider value={accountMemo}>
<CssBaseline />
<ErrorBoundary>
<Routes>

View File

@ -74,6 +74,8 @@ const EmojiPicker = (props) => {
inputProps={{
role: "searchbox",
"aria-label": t("emoji_picker_search_placeholder"),
}}
InputProps={{
endAdornment: (
<InputAdornment position="end" sx={{ display: search ? "" : "none" }}>
<IconButton size="small" onClick={handleSearchClear} edge="end" aria-label={t("emoji_picker_search_clear")}>

View File

@ -45,9 +45,8 @@ class ErrorBoundaryImpl extends React.Component {
// Fetch additional info and a better stack trace
StackTrace.fromError(error).then((stack) => {
console.error("[ErrorBoundary] Stacktrace fetched", stack);
const niceStack = `${error.toString()}\n${stack
.map((el) => ` at ${el.functionName} (${el.fileName}:${el.columnNumber}:${el.lineNumber})`)
.join("\n")}`;
const stackString = stack.map((el) => ` at ${el.functionName} (${el.fileName}:${el.columnNumber}:${el.lineNumber})`).join("\n");
const niceStack = `${error.toString()}\n${stackString}`;
this.setState({ niceStack });
});
}

View File

@ -383,23 +383,23 @@ const PublishDialog = (props) => {
"aria-label": t("publish_dialog_priority_label"),
}}
>
{[5, 4, 3, 2, 1].map((priorityMenuItem) => (
{[5, 4, 3, 2, 1].map((p) => (
<MenuItem
key={`priorityMenuItem${priorityMenuItem}`}
value={priorityMenuItem}
key={`priorityMenuItem${p}`}
value={p}
aria-label={t("notifications_priority_x", {
priority: priorityMenuItem,
priority: p,
})}
>
<div style={{ display: "flex", alignItems: "center" }}>
<img
src={priorities[priorityMenuItem].file}
src={priorities[p].file}
style={{ marginRight: "8px" }}
alt={t("notifications_priority_x", {
priority: priorityMenuItem,
priority: p,
})}
/>
<div>{priorities[priorityMenuItem].label}</div>
<div>{priorities[p].label}</div>
</div>
</MenuItem>
))}
@ -832,7 +832,10 @@ const ExpandingTextField = (props) => {
variant="standard"
sx={{ width: `${textWidth}px`, borderBottom: "none" }}
InputProps={{
style: { fontSize: theme.typography[props.variant].fontSize, paddingBottom: 0, paddingTop: 0 },
style: { fontSize: theme.typography[props.variant].fontSize },
}}
inputProps={{
style: { paddingBottom: 0, paddingTop: 0 },
"aria-label": props.placeholder,
}}
disabled={props.disabled}

View File

@ -247,6 +247,8 @@ const DisplayNameDialog = (props) => {
inputProps={{
maxLength: 64,
"aria-label": t("display_name_dialog_placeholder"),
}}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => setDisplayName("")} edge="end">

View File

@ -5,7 +5,7 @@ import react from "@vitejs/plugin-react";
export default defineConfig(() => ({
build: {
outDir: "build",
assetsDir: "static/media"
assetsDir: "static/media",
},
server: {
port: 3000,