From 55255cf9f40d81dbf5486850bcaca2b26e51bf6c Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Thu, 30 Mar 2023 15:11:23 -0400 Subject: [PATCH 01/58] Change use of 'user'/'users'/'number of users'/etc when referring to license seats to use 'seat'/'seats'/'number of seats'/etc. --- .../enterprise_edition/enterprise_edition_left_panel.tsx | 4 ++-- .../analytics/system_analytics/system_analytics.tsx | 2 +- webapp/channels/src/components/pricing_modal/content.tsx | 2 +- .../src/components/pricing_modal/self_hosted_content.tsx | 2 +- .../src/components/purchase_modal/purchase_modal.tsx | 2 +- webapp/channels/src/components/seats_calculator/index.tsx | 4 ++-- .../self_hosted_purchase_modal/self_hosted_card.tsx | 2 +- webapp/channels/src/i18n/de.json | 4 ---- webapp/channels/src/i18n/en.json | 8 ++++---- webapp/channels/src/i18n/en_AU.json | 8 ++++---- webapp/channels/src/i18n/es.json | 1 - webapp/channels/src/i18n/fa.json | 1 - webapp/channels/src/i18n/hu.json | 1 - webapp/channels/src/i18n/ja.json | 4 ---- webapp/channels/src/i18n/nl.json | 4 ---- webapp/channels/src/i18n/pl.json | 4 ---- webapp/channels/src/i18n/ru.json | 4 ---- webapp/channels/src/i18n/sv.json | 4 ---- webapp/channels/src/i18n/tr.json | 4 ---- 19 files changed, 17 insertions(+), 48 deletions(-) diff --git a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.tsx b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.tsx index c3f37bfd93..790272b3a5 100644 --- a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.tsx @@ -160,7 +160,7 @@ const EnterpriseEditionLeftPanel = ({ ); }; -type LegendValues = 'START DATE:' | 'EXPIRES:' | 'USERS:' | 'ACTIVE USERS:' | 'EDITION:' | 'LICENSE ISSUED:' | 'NAME:' | 'COMPANY / ORG:' +type LegendValues = 'START DATE:' | 'EXPIRES:' | 'LICENSED SEATS:' | 'ACTIVE USERS:' | 'EDITION:' | 'LICENSE ISSUED:' | 'NAME:' | 'COMPANY / ORG:' const renderLicenseValues = (activeUsers: number, seatsPurchased: number) => ({legend, value}: {legend: LegendValues; value: string | JSX.Element | null}, index: number): React.ReactNode => { if (legend === 'ACTIVE USERS:') { @@ -236,7 +236,7 @@ const renderLicenseContent = ( }> = [ {legend: 'START DATE:', value: startsAt}, {legend: 'EXPIRES:', value: expiresAt}, - {legend: 'USERS:', value: users}, + {legend: 'LICENSED SEATS:', value: users}, {legend: 'ACTIVE USERS:', value: activeUsers}, {legend: 'EDITION:', value: sku}, {legend: 'LICENSE ISSUED:', value: issued}, diff --git a/webapp/channels/src/components/analytics/system_analytics/system_analytics.tsx b/webapp/channels/src/components/analytics/system_analytics/system_analytics.tsx index b760279651..151941ee2a 100644 --- a/webapp/channels/src/components/analytics/system_analytics/system_analytics.tsx +++ b/webapp/channels/src/components/analytics/system_analytics/system_analytics.tsx @@ -348,7 +348,7 @@ export default class SystemAnalytics extends React.PureComponent { title={ } icon='fa-users' diff --git a/webapp/channels/src/components/pricing_modal/content.tsx b/webapp/channels/src/components/pricing_modal/content.tsx index e0f55999fe..b4712ec50f 100644 --- a/webapp/channels/src/components/pricing_modal/content.tsx +++ b/webapp/channels/src/components/pricing_modal/content.tsx @@ -396,7 +396,7 @@ function Content(props: ContentProps) { plan='Professional' planSummary={formatMessage({id: 'pricing_modal.planSummary.professional', defaultMessage: 'Scalable solutions for growing teams'})} price={`$${professionalPrice}`} - rate={formatMessage({id: 'pricing_modal.rate.userPerMonth', defaultMessage: 'USD per user/month {br}(billed annually)'}, { + rate={formatMessage({id: 'pricing_modal.rate.seatPerMonth', defaultMessage: 'USD per seat/month {br}(billed annually)'}, { br:
, b: (chunks: React.ReactNode | React.ReactNodeArray) => ( diff --git a/webapp/channels/src/components/pricing_modal/self_hosted_content.tsx b/webapp/channels/src/components/pricing_modal/self_hosted_content.tsx index 9edb86d824..67c1f8e69a 100644 --- a/webapp/channels/src/components/pricing_modal/self_hosted_content.tsx +++ b/webapp/channels/src/components/pricing_modal/self_hosted_content.tsx @@ -211,7 +211,7 @@ function SelfHostedContent(props: ContentProps) { plan='Professional' planSummary={formatMessage({id: 'pricing_modal.planSummary.professional', defaultMessage: 'Scalable solutions for growing teams'})} price={professionalPrice} - rate={formatMessage({id: 'pricing_modal.rate.userPerMonth', defaultMessage: 'USD per user/month {br}(billed annually)'}, { + rate={formatMessage({id: 'pricing_modal.rate.seatPerMonth', defaultMessage: 'USD per seat/month {br}(billed annually)'}, { br:
, b: (chunks: React.ReactNode | React.ReactNodeArray) => ( diff --git a/webapp/channels/src/components/purchase_modal/purchase_modal.tsx b/webapp/channels/src/components/purchase_modal/purchase_modal.tsx index 3fdfe6f319..41b67d198c 100644 --- a/webapp/channels/src/components/purchase_modal/purchase_modal.tsx +++ b/webapp/channels/src/components/purchase_modal/purchase_modal.tsx @@ -730,7 +730,7 @@ class PurchaseModal extends React.PureComponent { this.state.selectedProduct ? this.state.selectedProduct.name : '', )} price={yearlyProductMonthlyPrice} - rate={formatMessage({id: 'pricing_modal.rate.userPerMonth', defaultMessage: 'USD per user/month {br}(billed annually)'}, { + rate={formatMessage({id: 'pricing_modal.rate.seatPerMonth', defaultMessage: 'USD per seat/month {br}(billed annually)'}, { br:
, b: (chunks: React.ReactNode | React.ReactNodeArray) => ( diff --git a/webapp/channels/src/components/seats_calculator/index.tsx b/webapp/channels/src/components/seats_calculator/index.tsx index 57c3436576..9776868d71 100644 --- a/webapp/channels/src/components/seats_calculator/index.tsx +++ b/webapp/channels/src/components/seats_calculator/index.tsx @@ -167,7 +167,7 @@ export default function SeatsCalculator(props: Props) { type='text' value={props.seats.quantity} onChange={onChange} - placeholder={intl.formatMessage({id: 'self_hosted_signup.seats', defaultMessage: 'User seats'})} + placeholder={intl.formatMessage({id: 'self_hosted_signup.seats', defaultMessage: 'Seats'})} wrapperClassName='user_seats' inputClassName='user_seats' maxLength={maxSeats.toString().length + 1} @@ -197,7 +197,7 @@ export default function SeatsCalculator(props: Props) {
(billed annually)'}, { + rate={intl.formatMessage({id: 'pricing_modal.rate.seatPerMonth', defaultMessage: 'USD per seat/month {br}(billed annually)'}, { br:
, b: (chunks: React.ReactNode | React.ReactNodeArray) => ( diff --git a/webapp/channels/src/i18n/de.json b/webapp/channels/src/i18n/de.json index 01990e3010..cd3fbe5c63 100644 --- a/webapp/channels/src/i18n/de.json +++ b/webapp/channels/src/i18n/de.json @@ -2576,7 +2576,6 @@ "analytics.system.postTypes": "Nachrichten, Dateien und Hashtags", "analytics.system.privateGroups": "Private Kanäle", "analytics.system.publicChannels": "Öffentliche Kanäle", - "analytics.system.seatsPurchased": "Total bezahlte Nutzer", "analytics.system.skippedIntensiveQueries": "Um die Performance zu maximieren, sind einige Statistiken deaktiviert. Du kannst sie in der config.json reaktivieren.", "analytics.system.textPosts": "Nur-Text Beiträge", "analytics.system.title": "Systemstatistiken", @@ -4577,7 +4576,6 @@ "pricing_modal.planSummary.professional": "Skalierbare Lösungen für wachsende Teams", "pricing_modal.plan_label_trialDays": "{days} TAGE, DIE IM TEST VERBLEIBEN", "pricing_modal.price.freeForever": "Kostenlos für immer", - "pricing_modal.rate.userPerMonth": "USD pro Benutzer/Monat {br}(jährliche Abrechnung)", "pricing_modal.reviewDeploymentOptions": "Prüfe deine Bereitstellungsoptionen", "pricing_modal.start_trial.disclaimer": "Durch Auswahl von 30 Tage lang kostenlos testen, stimme ich dem Mattermost Software und Services License Agreement, der Datenschutz-Richtlinie und dem Erhalt von Produkt-E-Mails zu.", "pricing_modal.subtitle": "Wähle einen Plan um loszulegen", @@ -4720,7 +4718,6 @@ "self_hosted_signup.failed_export.subtitle": "Wir werden die Dinge von unserer Seite aus überprüfen und uns innerhalb von 3 Tagen bei dir melden, sobald deine Lizenz genehmigt ist. In der Zwischenzeit kannst du gerne die kostenlose Version unseres Produkts weiter nutzen.", "self_hosted_signup.failed_export.title": "Deine Transaktion wird überprüft", "self_hosted_signup.license_applied": "Deine {planName} Lizenz wurde jetzt angewendet. {planName} Funktionen sind jetzt verfügbar und einsatzbereit.", - "self_hosted_signup.line_item_subtotal": "{num} Nutzer × 12 Mo.", "self_hosted_signup.organization": "Name der Organisation", "self_hosted_signup.progress_step.applying_license": "Übertrage deine {planName} Lizenz auf deine Mattermost-Instanz", "self_hosted_signup.progress_step.submitting_payment": "Übermittlung von Zahlungsinformationen", @@ -4733,7 +4730,6 @@ "self_hosted_signup.retry": "Erneut versuchen", "self_hosted_signup.screening_description": "Wir werden die Dinge von unserer Seite aus überprüfen und uns innerhalb von 3 Tagen bei dir melden, sobald deine Lizenz genehmigt ist. In der Zwischenzeit kannst du gerne die kostenlose Version unseres Produkts weiter nutzen.", "self_hosted_signup.screening_title": "Deine Transaktion wird überprüft", - "self_hosted_signup.seats": "Benutzerplätze", "self_hosted_signup.signup_consequences": "Du erhältst eine Rechnung von heute. Deine Lizenz wird automatisch angewendet. Sieh, wie die Abrechnung funktioniert.", "self_hosted_signup.total": "Summe", "setting_item_max.cancel": "Abbrechen", diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index 6f147fa4ee..6061ac68d6 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -2575,7 +2575,7 @@ "analytics.system.postTypes": "Posts, Files and Hashtags", "analytics.system.privateGroups": "Private Channels", "analytics.system.publicChannels": "Public Channels", - "analytics.system.seatsPurchased": "Total paid users", + "analytics.system.seatsPurchased": "Licensed Seats", "analytics.system.skippedIntensiveQueries": "To maximize performance, some statistics are disabled. You can re-enable them in config.json.", "analytics.system.textPosts": "Posts with Text-only", "analytics.system.title": "System Statistics", @@ -4569,7 +4569,7 @@ "pricing_modal.planSummary.free": "Increased productivity for small teams", "pricing_modal.planSummary.professional": "Scalable solutions for growing teams", "pricing_modal.price.freeForever": "Free forever", - "pricing_modal.rate.userPerMonth": "USD per user/month {br}(billed annually)", + "pricing_modal.rate.seatPerMonth": "USD per seat/month {br}(billed annually)", "pricing_modal.reviewDeploymentOptions": "Review deployment options", "pricing_modal.start_trial.disclaimer": "By selecting Try free for 30 days, I agree to the Mattermost Software and Services License Agreement, Privacy Policy, and receiving product emails.", "pricing_modal.subtitle": "Choose a plan to get started", @@ -4712,7 +4712,7 @@ "self_hosted_signup.failed_export.subtitle": "We will check things on our side and get back to you within 3 days once your license is approved. In the meantime, please feel free to continue using the free version of our product.", "self_hosted_signup.failed_export.title": "Your transaction is being reviewed", "self_hosted_signup.license_applied": "Your {planName} license has now been applied. {planName} features are now available and ready to use.", - "self_hosted_signup.line_item_subtotal": "{num} users × 12 mo.", + "self_hosted_signup.line_item_subtotal": "{num} seats × 12 mo.", "self_hosted_signup.organization": "Organization Name", "self_hosted_signup.progress_step.applying_license": "Applying your {planName} license to your Mattermost instance", "self_hosted_signup.progress_step.submitting_payment": "Submitting payment information", @@ -4725,7 +4725,7 @@ "self_hosted_signup.retry": "Try again", "self_hosted_signup.screening_description": "We will check things on our side and get back to you within 3 days once your license is approved. In the meantime, please feel free to continue using the free version of our product.", "self_hosted_signup.screening_title": "Your transaction is being reviewed", - "self_hosted_signup.seats": "User seats", + "self_hosted_signup.seats": "Seats", "self_hosted_signup.signup_consequences": "You will be billed today. Your license will be applied automatically. See how billing works.", "self_hosted_signup.total": "Total", "setting_item_max.cancel": "Cancel", diff --git a/webapp/channels/src/i18n/en_AU.json b/webapp/channels/src/i18n/en_AU.json index a8a38f34e8..b8c9128aae 100644 --- a/webapp/channels/src/i18n/en_AU.json +++ b/webapp/channels/src/i18n/en_AU.json @@ -2572,7 +2572,7 @@ "analytics.system.postTypes": "Posts, Files and Hashtags", "analytics.system.privateGroups": "Private Channels", "analytics.system.publicChannels": "Public Channels", - "analytics.system.seatsPurchased": "Total paid users", + "analytics.system.seatsPurchased": "Licensed Seats", "analytics.system.skippedIntensiveQueries": "To maximise performance, some statistics are disabled. You can re-enable them in config.json.", "analytics.system.textPosts": "Posts with Text-only", "analytics.system.title": "System Statistics", @@ -4540,7 +4540,7 @@ "pricing_modal.planSummary.professional": "Scalable solutions for growing teams", "pricing_modal.plan_label_trialDays": "{days} DAYS LEFT ON TRIAL", "pricing_modal.price.freeForever": "Free forever", - "pricing_modal.rate.userPerMonth": "USD per user/month {br}(billed annually)", + "pricing_modal.rate.seatPerMonth": "USD per seat/month {br}(billed annually)", "pricing_modal.reviewDeploymentOptions": "Review deployment options", "pricing_modal.start_trial.disclaimer": "By selecting Try free for 30 days, I agree to the Mattermost Software and Services Licence Agreement, Privacy Policy and receiving product emails.", "pricing_modal.subtitle": "Choose a plan to get started", @@ -4683,7 +4683,7 @@ "self_hosted_signup.failed_export.subtitle": "You will receive an email within 3 days to confirm the approval of your licence. In the meantime, please feel free to continue using the free version of our product.", "self_hosted_signup.failed_export.title": "Your transaction is being reviewed", "self_hosted_signup.license_applied": "Your {planName} licence has now been applied. {planName} features are now available and ready to use.", - "self_hosted_signup.line_item_subtotal": "{num} users × 12 months.", + "self_hosted_signup.line_item_subtotal": "{num} seats × 12 months.", "self_hosted_signup.organization": "Organisation Name", "self_hosted_signup.progress_step.applying_license": "Applying your {planName} licence to your Mattermost instance", "self_hosted_signup.progress_step.submitting_payment": "Submitting payment information", @@ -4696,7 +4696,7 @@ "self_hosted_signup.retry": "Try again", "self_hosted_signup.screening_description": "You will receive an email within 3 days to confirm the approval of your licence. In the meantime, please feel free to continue using the free version of our product.", "self_hosted_signup.screening_title": "Your transaction is being reviewed", - "self_hosted_signup.seats": "User seats", + "self_hosted_signup.seats": "Seats", "self_hosted_signup.signup_consequences": "You will be billed today. Your licence will be applied automatically. See how billing works.", "self_hosted_signup.total": "Total", "setting_item_max.cancel": "Cancel", diff --git a/webapp/channels/src/i18n/es.json b/webapp/channels/src/i18n/es.json index 28de93f5e2..2730763abe 100644 --- a/webapp/channels/src/i18n/es.json +++ b/webapp/channels/src/i18n/es.json @@ -4176,7 +4176,6 @@ "pricing_modal.planSummary.enterprise": "Administración, seguridad y cumplimiento para grandes equipos", "pricing_modal.plan_label_trialDays": "{days} DÍAS RESTANTES DE LA PRUEBA", "pricing_modal.price.freeForever": "Libre por siempre", - "pricing_modal.rate.userPerMonth": "/usuario/mes", "pricing_modal.subtitle": "Elige un plan para empezar", "promote_to_user_modal.desc": "Esta acción promueve al huésped {username} a miembro. Esto permitirá que el usuario se pueda unir a canales públicos y pueda interactuar con usuarios fuera de los canales de los cuales es miembro actualmente. ¿Está seguro que desea promover al huésped {username} a miembro?", "promote_to_user_modal.promote": "Promover", diff --git a/webapp/channels/src/i18n/fa.json b/webapp/channels/src/i18n/fa.json index 90132c93a1..86af91132c 100644 --- a/webapp/channels/src/i18n/fa.json +++ b/webapp/channels/src/i18n/fa.json @@ -4089,7 +4089,6 @@ "self_hosted_signup.organization": "نام سازمان", "self_hosted_signup.purchase_in_progress.reset": "شروع دوباره خرید", "self_hosted_signup.retry": "تلاش دوباره", - "self_hosted_signup.seats": "نشست‌های کاربران", "self_hosted_signup.total": "جمع", "setting_item_max.cancel": "انصراف", "setting_item_min.edit": "ویرایش کنید", diff --git a/webapp/channels/src/i18n/hu.json b/webapp/channels/src/i18n/hu.json index cf69f79c4c..aa0bfebfb6 100644 --- a/webapp/channels/src/i18n/hu.json +++ b/webapp/channels/src/i18n/hu.json @@ -4238,7 +4238,6 @@ "pricing_modal.planSummary.professional": "Skálázható megoldások növekvő csapatok számára", "pricing_modal.plan_label_trialDays": "{days} NAP VAN HÁTRA A PRÓBAIDŐSZAKBÓL", "pricing_modal.price.freeForever": "Örökké ingyenes", - "pricing_modal.rate.userPerMonth": "/felhasználó/hónap", "pricing_modal.reviewDeploymentOptions": "A telepítési lehetőségek áttekintése", "pricing_modal.subtitle": "Válasszon egy csomagot az induláshoz", "pricing_modal.title": "Válasszon csomagot", diff --git a/webapp/channels/src/i18n/ja.json b/webapp/channels/src/i18n/ja.json index fee7cc2e97..f2804b5e0d 100644 --- a/webapp/channels/src/i18n/ja.json +++ b/webapp/channels/src/i18n/ja.json @@ -2576,7 +2576,6 @@ "analytics.system.postTypes": "投稿、ファイル、ハッシュタグ", "analytics.system.privateGroups": "非公開チャンネル", "analytics.system.publicChannels": "公開チャンネル", - "analytics.system.seatsPurchased": "有償ユーザー数", "analytics.system.skippedIntensiveQueries": "パフォーマンスを最大化するため無効化された統計情報があります。 config.jsonから、それらを再度有効にすることができます。", "analytics.system.textPosts": "テキストのみの投稿数", "analytics.system.title": "システムの使用統計", @@ -4577,7 +4576,6 @@ "pricing_modal.planSummary.professional": "成長するチームのためのスケーラブルなソリューション", "pricing_modal.plan_label_trialDays": "トライアル残り日数 {days}", "pricing_modal.price.freeForever": "永久無料", - "pricing_modal.rate.userPerMonth": "USD ユーザー/月 {br}(年間請求)", "pricing_modal.reviewDeploymentOptions": "デプロイオプションを確認する", "pricing_modal.start_trial.disclaimer": "30日間のトライアルを開始するを選択すると、Mattermost Software and Services License Agreementプライバシーポリシー に同意したことになり、製品に関する電子メールを受信するようになります。", "pricing_modal.subtitle": "プランを選んで開始", @@ -4720,7 +4718,6 @@ "self_hosted_signup.failed_export.subtitle": "あなたのライセンスが承認され次第、弊社側で確認を行い、3日以内に返信いたします。それまでの間は、Free版の製品を引き続きご利用ください。", "self_hosted_signup.failed_export.title": "取引きは審査中です", "self_hosted_signup.license_applied": "{planName} ライセンスが適用されました。{planName} の機能が利用可能になり、今すぐ使用することができます。", - "self_hosted_signup.line_item_subtotal": "{num} ユーザー x 12ヶ月。", "self_hosted_signup.organization": "組織名", "self_hosted_signup.progress_step.applying_license": "Mattermostインスタンスに {planName} ライセンスを適用しています", "self_hosted_signup.progress_step.submitting_payment": "支払い情報を提出する", @@ -4733,7 +4730,6 @@ "self_hosted_signup.retry": "際実行", "self_hosted_signup.screening_description": "あなたのライセンスが承認され次第、弊社側で確認を行い、3日以内に返信いたします。それまでの間は、Free版の製品を引き続きご利用ください。", "self_hosted_signup.screening_title": "取引きは審査中です", - "self_hosted_signup.seats": "ユーザーシート", "self_hosted_signup.signup_consequences": "本日課金されます。あなたのライセンスは自動で適用されます。課金の仕組みについてはこちらを参照してください。", "self_hosted_signup.total": "合計", "setting_item_max.cancel": "キャンセル", diff --git a/webapp/channels/src/i18n/nl.json b/webapp/channels/src/i18n/nl.json index 2b0c2deccf..d643a8523c 100644 --- a/webapp/channels/src/i18n/nl.json +++ b/webapp/channels/src/i18n/nl.json @@ -2574,7 +2574,6 @@ "analytics.system.postTypes": "Berichten, bestanden en hashtags", "analytics.system.privateGroups": "Privé-kanalen", "analytics.system.publicChannels": "Publieke kanalen", - "analytics.system.seatsPurchased": "Totaal aantal betaalde gebruikers", "analytics.system.skippedIntensiveQueries": "Om de prestaties te maximaliseren, zijn sommige statistieken uitgeschakeld. Je kan deze opnieuw inschakelen in config.json .", "analytics.system.textPosts": "Berichten met enkel tekst", "analytics.system.title": "Systeem-statistieken", @@ -4562,7 +4561,6 @@ "pricing_modal.planSummary.professional": "Schaalbare oplossingen voor groeiende teams", "pricing_modal.plan_label_trialDays": "{days} DAGEN OVER VAN PROEFPERIODE", "pricing_modal.price.freeForever": "Voor altijd gratis", - "pricing_modal.rate.userPerMonth": "USD per gebruiker/maand{br}(Jaarlijks gefactureerd)", "pricing_modal.reviewDeploymentOptions": "Bekijk de installatiemogelijkheden", "pricing_modal.start_trial.disclaimer": "Door Gratis 30 dagen proberen, te selecteren ga ik akkoord met de Mattermost Software Evaluatie Overeenkomst, Privacy Beleid, en het ontvangen van product emails.", "pricing_modal.subtitle": "Kies een plan om te beginnen", @@ -4705,7 +4703,6 @@ "self_hosted_signup.failed_export.subtitle": "Wij controleren de zaken aan onze kant en nemen binnen 3 dagen contact met jou op zodra jouuw licentie is goedgekeurd. In de tussentijd kan je gerust de gratis versie van ons product blijven gebruiken.", "self_hosted_signup.failed_export.title": "Jouw transactie wordt bekeken", "self_hosted_signup.license_applied": "Jouw {planName} licentie is nu toegepast. {planName} functies zijn nu beschikbaar en klaar voor gebruik.", - "self_hosted_signup.line_item_subtotal": "{num} gebruikers × 12 maanden.", "self_hosted_signup.organization": "Naam organisatie", "self_hosted_signup.progress_step.applying_license": "Jouw {planName} licentie toepassen op jouw Mattermost instantie", "self_hosted_signup.progress_step.submitting_payment": "Betalingsinformatie indienen", @@ -4718,7 +4715,6 @@ "self_hosted_signup.retry": "Probeer opnieuw", "self_hosted_signup.screening_description": "Wij controleren de zaken aan onze kant en nemen binnen 3 dagen contact met jou op zodra jouuw licentie is goedgekeurd. In de tussentijd kan je gerust de gratis versie van ons product blijven gebruiken.", "self_hosted_signup.screening_title": "Jouw transactie wordt bekeken", - "self_hosted_signup.seats": "Gebruikersstoelen", "self_hosted_signup.signup_consequences": "Je wordt gefactureerd op *today*. Jouw licentie wordt automatisch toegepast. Zie hoe facturering werkt.", "self_hosted_signup.total": "Totaal", "setting_item_max.cancel": "Annuleren", diff --git a/webapp/channels/src/i18n/pl.json b/webapp/channels/src/i18n/pl.json index 96eda0f3b4..be3310220a 100644 --- a/webapp/channels/src/i18n/pl.json +++ b/webapp/channels/src/i18n/pl.json @@ -2576,7 +2576,6 @@ "analytics.system.postTypes": "Wiadomości, Pliki i Hashtagi", "analytics.system.privateGroups": "Kanały prywatne", "analytics.system.publicChannels": "Kanały publiczne", - "analytics.system.seatsPurchased": "Całkowita liczba użytkowników płatnych", "analytics.system.skippedIntensiveQueries": "Aby zmaksymalizować wydajność, niektóre statystyki są wyłączone. Możesz ponownie je włączyć w config.json.", "analytics.system.textPosts": "Wiadomości z samym tekstem", "analytics.system.title": "Statystyki systemu", @@ -4577,7 +4576,6 @@ "pricing_modal.planSummary.professional": "Skalowalne rozwiązania dla rozwijających się zespołów", "pricing_modal.plan_label_trialDays": "{days} POZOSTAŁO DNI TESTOWYCH", "pricing_modal.price.freeForever": "Bezpłatny na zawsze", - "pricing_modal.rate.userPerMonth": "USD za użytkownika/miesiąc {br}(rozliczane rocznie)", "pricing_modal.reviewDeploymentOptions": "Zapoznaj się z opcjami rozmieszczania", "pricing_modal.start_trial.disclaimer": "Wybierając opcję Wypróbuj przez 30 dni, wyrażam zgodę na Mattermost Software and Services License Agreement, Privacy Policy oraz na otrzymywanie wiadomości e-mail dotyczących produktu.", "pricing_modal.subtitle": "Wybierz plan, aby rozpocząć pracę", @@ -4720,7 +4718,6 @@ "self_hosted_signup.failed_export.subtitle": "Sprawdzimy wszystko po naszej stronie i skontaktujemy się z Tobą w ciągu 3 dni po zatwierdzeniu licencji. W międzyczasie prosimy o dalsze korzystanie z darmowej wersji naszego produktu.", "self_hosted_signup.failed_export.title": "Twoja transakcja jest sprawdzana", "self_hosted_signup.license_applied": "Twoja licencja {planName} została zastosowana. Funkcje {planName} są teraz dostępne i gotowe do użycia.", - "self_hosted_signup.line_item_subtotal": "{num} użytkownicy × 12-cy.", "self_hosted_signup.organization": "Nazwa organizacji", "self_hosted_signup.progress_step.applying_license": "Zastosowanie licencji {planName} do instancji Mattermost", "self_hosted_signup.progress_step.submitting_payment": "Przekazanie informacji o płatności", @@ -4733,7 +4730,6 @@ "self_hosted_signup.retry": "Spróbuj ponownie", "self_hosted_signup.screening_description": "Sprawdzimy wszystko po naszej stronie i skontaktujemy się z Tobą w ciągu 3 dni po zatwierdzeniu licencji. W międzyczasie prosimy o dalsze korzystanie z darmowej wersji naszego produktu.", "self_hosted_signup.screening_title": "Twoja transakcja jest sprawdzana", - "self_hosted_signup.seats": "Miejsca dla użytkowników", "self_hosted_signup.signup_consequences": "Zostaniesz rozliczony dzisiaj. Twoja licencja zostanie zastosowana automatycznie. Zobacz jak działa rozliczenie.", "self_hosted_signup.total": "Ogółem", "setting_item_max.cancel": "Anuluj", diff --git a/webapp/channels/src/i18n/ru.json b/webapp/channels/src/i18n/ru.json index bfca5442bf..6490e1b2b9 100644 --- a/webapp/channels/src/i18n/ru.json +++ b/webapp/channels/src/i18n/ru.json @@ -2576,7 +2576,6 @@ "analytics.system.postTypes": "Сообщения, файлы и хештэги", "analytics.system.privateGroups": "Приватные каналы", "analytics.system.publicChannels": "Публичные каналы", - "analytics.system.seatsPurchased": "Всего платных пользователей", "analytics.system.skippedIntensiveQueries": "Для обеспечения максимальной производительности некоторые статистические данные отключены. Вы можете повторно включить их в config.json.", "analytics.system.textPosts": "Только текстовые сообщения", "analytics.system.title": "Статистика системы", @@ -4564,7 +4563,6 @@ "pricing_modal.planSummary.professional": "Масштабируемые решения для растущих команд", "pricing_modal.plan_label_trialDays": "ОСТАЛОСЬ {days} ДНЕЙ НА ПРОБНУЮ ВЕРСИЮ", "pricing_modal.price.freeForever": "Бесплатно навсегда", - "pricing_modal.rate.userPerMonth": "USD за пользователя/месяц {br}(счет ежегодно)", "pricing_modal.reviewDeploymentOptions": "Обзор вариантов развертывания", "pricing_modal.start_trial.disclaimer": "Выбирая Попробовать бесплатно в течение 30 дней, я соглашаюсь с лицензионным соглашением на программное обеспечение и услуги Mattermost, политикой конфиденциальности, а также с получением электронных сообщений о продукте.", "pricing_modal.subtitle": "Выберите план, чтобы начать работу", @@ -4707,7 +4705,6 @@ "self_hosted_signup.failed_export.subtitle": "Мы проверим ситуацию на нашей стороне и свяжемся с вами в течение 3 дней, когда ваша лицензия будет одобрена. Тем временем, пожалуйста, продолжайте пользоваться бесплатной версией нашего продукта.", "self_hosted_signup.failed_export.title": "Ваша транзакция находится на рассмотрении", "self_hosted_signup.license_applied": "Ваша лицензия {planName} была применена. Функции {planName} теперь доступны и готовы к использованию.", - "self_hosted_signup.line_item_subtotal": "{num} пользователи × 12 мес.", "self_hosted_signup.organization": "Название организации", "self_hosted_signup.progress_step.applying_license": "Применение лицензии {planName} к экземпляру Mattermost", "self_hosted_signup.progress_step.submitting_payment": "Предоставление платежной информации", @@ -4720,7 +4717,6 @@ "self_hosted_signup.retry": "Попробовать снова", "self_hosted_signup.screening_description": "Мы проверим ситуацию на нашей стороне и свяжемся с вами в течение 3 дней, когда ваша лицензия будет одобрена. Тем временем, пожалуйста, продолжайте пользоваться бесплатной версией нашего продукта.", "self_hosted_signup.screening_title": "Ваша транзакция находится на рассмотрении", - "self_hosted_signup.seats": "Пользовательские места", "self_hosted_signup.signup_consequences": "Сегодня Вам будет выставлен счет. Ваша лицензия будет применена автоматически. Узнайте, как происходит выставление счетов.", "self_hosted_signup.total": "Всего", "setting_item_max.cancel": "Отмена", diff --git a/webapp/channels/src/i18n/sv.json b/webapp/channels/src/i18n/sv.json index 9ed2615d87..c52f96f039 100644 --- a/webapp/channels/src/i18n/sv.json +++ b/webapp/channels/src/i18n/sv.json @@ -2576,7 +2576,6 @@ "analytics.system.postTypes": "Meddelanden, filer och hashtags", "analytics.system.privateGroups": "Privat kanal", "analytics.system.publicChannels": "Publika kanaler", - "analytics.system.seatsPurchased": "Totala betalande användare", "analytics.system.skippedIntensiveQueries": "För att maximera prestanda så är viss statistik inaktiverad. Du kan aktivera dem i config.json.", "analytics.system.textPosts": "Meddelanden med endast text", "analytics.system.title": "Site statistik", @@ -4564,7 +4563,6 @@ "pricing_modal.planSummary.professional": "Skalbara lösningar för växande team", "pricing_modal.plan_label_trialDays": "{days} DAGAR KVAR AV PROVA-PÅ-PERIODEN", "pricing_modal.price.freeForever": "Gratis för alltid", - "pricing_modal.rate.userPerMonth": "USD per användare/månad {br}(faktureras årligen)", "pricing_modal.reviewDeploymentOptions": "Granska dina utrullningsalternativ", "pricing_modal.start_trial.disclaimer": "Genom att välja Testa gratis i 30 dagar, godkänner jag Mattermost Software and Services License Agreement, Privacy Policy och att få mejl med produktinformation.", "pricing_modal.subtitle": "Välj ett abonnemang för att komma igång", @@ -4707,7 +4705,6 @@ "self_hosted_signup.failed_export.subtitle": "Vi kommer kontrollera några saker på vår sida och när din licens är godkänd återkommer vi till dig inom tre dagar. Under tiden kan du gärna fortsätta att använda gratisversionen av vår produkt.", "self_hosted_signup.failed_export.title": "Din transaktion granskas", "self_hosted_signup.license_applied": "Din {planName} -licens har nu tillämpats. {planName} -funktionerna är nu tillgängliga och redo att användas.", - "self_hosted_signup.line_item_subtotal": "{num} användare × 12 månader.", "self_hosted_signup.organization": "Organisationens namn", "self_hosted_signup.progress_step.applying_license": "Applicerar din {planName} -licens på din Mattermost-instans", "self_hosted_signup.progress_step.submitting_payment": "Lämna betalningsuppgifter", @@ -4720,7 +4717,6 @@ "self_hosted_signup.retry": "Försök igen", "self_hosted_signup.screening_description": "Vi kommer att kontrollera saker och ting från vår sida och återkommer till dig inom tre dagar när din licens är godkänd. Under tiden kan du gärna fortsätta att använda gratisversionen av vår produkt.", "self_hosted_signup.screening_title": "Din transaktion håller på att granskas", - "self_hosted_signup.seats": "Användarplatser", "self_hosted_signup.signup_consequences": "Du kommer att debiteras idag. Din licens tillämpas automatiskt. Se hur faktureringen fungerar.", "self_hosted_signup.total": "Summa", "setting_item_max.cancel": "Avbryt", diff --git a/webapp/channels/src/i18n/tr.json b/webapp/channels/src/i18n/tr.json index 4c4e6c1fed..588a76ce27 100644 --- a/webapp/channels/src/i18n/tr.json +++ b/webapp/channels/src/i18n/tr.json @@ -2534,7 +2534,6 @@ "analytics.system.postTypes": "İletiler, dosyalar ve hashtaglar", "analytics.system.privateGroups": "Özel kanallar", "analytics.system.publicChannels": "Herkese açık kanallar", - "analytics.system.seatsPurchased": "Ücreti ödenmiş kullanıcı sayısı", "analytics.system.skippedIntensiveQueries": "En iyi başarımı elde etmek için bazı istatistikler devre dışı bırakılmıştır. Bu istatistikleri config.json içinden etkinleştirebilirsiniz.", "analytics.system.textPosts": "Yalnızca metin içeren iletiler", "analytics.system.title": "Sistem istatistikleri", @@ -4466,7 +4465,6 @@ "pricing_modal.planSummary.professional": "Büyük ekipler için yönetim, güvenlik ve uygunluk", "pricing_modal.plan_label_trialDays": "DENEMENİN BİTMESİNE {days} GÜN KALDI", "pricing_modal.price.freeForever": "Sonsuza dek ücretsiz", - "pricing_modal.rate.userPerMonth": "USD kullanıcı/ay{br}(yıllık faturalanır)", "pricing_modal.reviewDeploymentOptions": "Dağıtım seçeneklerini gözden geçirin", "pricing_modal.start_trial.disclaimer": "30 günlük ücretsiz denemeyi başlat üzerine tıklayarak, Mattermost yazılım ve hizmet lisans sözleşmesi, Kişisel verilerin gizliliği ilkesi metinlerini ve ürün ile ilgili e-postaları almayı kabul ediyorum.", "pricing_modal.subtitle": "Başlamak için bir tarife seçin", @@ -4608,7 +4606,6 @@ "self_hosted_signup.failed_export.subtitle": "Kontrollerimizi yapacağız ve lisansınızı onaylandıktan sonra 3 gün içinde size geri döneceğiz. Bu arada, lütfen ürünümüzün ücretsiz sürümünü kullanmayı sürdürmekten çekinmeyin.", "self_hosted_signup.failed_export.title": "İşleminiz inceleniyor", "self_hosted_signup.license_applied": "{planName} lisansınız etkinleştirildi. {planName} özelliklerini kullanabilirsiniz.", - "self_hosted_signup.line_item_subtotal": "{num} kullanıcı × 12 ay.", "self_hosted_signup.organization": "Kuruluş adı", "self_hosted_signup.progress_step.applying_license": "{planName} lisansınız Mattermost kopyanıza uygulanıyor", "self_hosted_signup.progress_step.submitting_payment": "Ödeme bilgileri gönderiliyor", @@ -4621,7 +4618,6 @@ "self_hosted_signup.retry": "Yeniden dene", "self_hosted_signup.screening_description": "Kontrollerimizi yapacağız ve lisansınızı onaylandıktan sonra 3 gün içinde size geri döneceğiz. Bu arada, lütfen ürünümüzün ücretsiz sürümünü kullanmayı sürdürmekten çekinmeyin.", "self_hosted_signup.screening_title": "İşleminiz inceleniyor", - "self_hosted_signup.seats": "Kullanıcı koltuk lisansı", "self_hosted_signup.signup_consequences": "Faturanız bugün kesilecek. Lisansınız otomatik olarak etkinleştirilecek. Faturalamanın nasıl işlediğine bakın.", "self_hosted_signup.total": "Toplam", "setting_item_max.cancel": "İptal", From 9791f74602e947d4e4d73cab5e24ff0755fd9e6d Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Thu, 30 Mar 2023 15:54:03 -0400 Subject: [PATCH 02/58] more user/seat wording changes. --- .../billing/invoice_user_count.tsx | 29 +++++++++---------- .../analytics/activated_users_card/index.tsx | 2 +- webapp/channels/src/i18n/bg.json | 1 - webapp/channels/src/i18n/de.json | 5 ---- webapp/channels/src/i18n/en.json | 9 +++--- webapp/channels/src/i18n/en_AU.json | 10 +++---- webapp/channels/src/i18n/es.json | 3 -- webapp/channels/src/i18n/fa.json | 2 -- webapp/channels/src/i18n/fr.json | 4 --- webapp/channels/src/i18n/hu.json | 3 -- webapp/channels/src/i18n/it.json | 3 -- webapp/channels/src/i18n/ja.json | 5 ---- webapp/channels/src/i18n/ko.json | 4 --- webapp/channels/src/i18n/nl.json | 5 ---- webapp/channels/src/i18n/pl.json | 5 ---- webapp/channels/src/i18n/pt-BR.json | 3 -- webapp/channels/src/i18n/ro.json | 1 - webapp/channels/src/i18n/ru.json | 5 ---- webapp/channels/src/i18n/sv.json | 5 ---- webapp/channels/src/i18n/tr.json | 5 ---- webapp/channels/src/i18n/zh-CN.json | 4 --- 21 files changed, 24 insertions(+), 89 deletions(-) diff --git a/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx b/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx index 896b7f0b63..20d17c0bb1 100644 --- a/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx +++ b/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx @@ -18,10 +18,9 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele if (onPremUsers) { return ( ); @@ -45,10 +44,10 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele return ( ); @@ -56,11 +55,11 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele return ( ); diff --git a/webapp/channels/src/components/analytics/activated_users_card/index.tsx b/webapp/channels/src/components/analytics/activated_users_card/index.tsx index 1f4d6c68a3..cce7ac420c 100644 --- a/webapp/channels/src/components/analytics/activated_users_card/index.tsx +++ b/webapp/channels/src/components/analytics/activated_users_card/index.tsx @@ -56,7 +56,7 @@ export const ActivatedUserCard = ({activatedUsers, seatsPurchased, isCloud}: Act /> {(text) => {text}} diff --git a/webapp/channels/src/i18n/bg.json b/webapp/channels/src/i18n/bg.json index c5331d8e9c..6aabdc38d5 100644 --- a/webapp/channels/src/i18n/bg.json +++ b/webapp/channels/src/i18n/bg.json @@ -242,7 +242,6 @@ "admin.billing.history.title": "История на плащания", "admin.billing.history.total": "Общо", "admin.billing.history.transactions": "Транзакции", - "admin.billing.history.usersAndRates": "{fullUsers} потребители на пълна тарифа, {partialUsers} потребители с частично таксуване", "admin.billing.payment_info.add": "Добави кредитна карта", "admin.billing.payment_info.billingAddress": "Адрес за фактуриране", "admin.billing.payment_info.cardBrandAndDigits": "{brand} завършва на {digits}", diff --git a/webapp/channels/src/i18n/de.json b/webapp/channels/src/i18n/de.json index cd3fbe5c63..56c0a379f1 100644 --- a/webapp/channels/src/i18n/de.json +++ b/webapp/channels/src/i18n/de.json @@ -265,10 +265,7 @@ "admin.billing.history.allPaymentsShowHere": "Alle deine Rechnungen werden hier angezeigt", "admin.billing.history.date": "Datum", "admin.billing.history.description": "Beschreibung", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} gebührenpflichtige Nutzer, {fullUsers} Nutzer zum vollen Tarif, {partialUsers} Nutzer mit Teilgebühren", - "admin.billing.history.fractionalUsers": "{fractionalUsers} Benutzer", "admin.billing.history.noBillingHistory": "Hier wird in Zukunft deine Abrechnungshistorie angezeigt.", - "admin.billing.history.onPremUsers": "{num} Benutzer", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} von {totalRecords}", "admin.billing.history.paid": "Bezahlt", "admin.billing.history.paymentFailed": "Zahlungsvorgang fehlgeschlagen", @@ -278,7 +275,6 @@ "admin.billing.history.title": "Abrechnungshistorie", "admin.billing.history.total": "Total", "admin.billing.history.transactions": "Transaktionen", - "admin.billing.history.usersAndRates": "{fullUsers} Nutzer auf Vollrate, {partialUsers} Nutzer auf Teilrate", "admin.billing.payment_info.add": "Kreditkarte hinzufügen", "admin.billing.payment_info.billingAddress": "Rechnungsadresse", "admin.billing.payment_info.cardBrandAndDigits": "{brand} endet mit {digits}", @@ -2595,7 +2591,6 @@ "analytics.team.activeUsers": "Aktive Benutzer mit Beiträgen", "analytics.team.newlyCreated": "Neu erstellte Benutzer", "analytics.team.noTeams": "Auf diesem Server gibt es keine Teams, für die Statistiken eingesehen werden können.", - "analytics.team.overageUsersSeats": "Dies übersteigt die Zahl der bezahlten Nutzer", "analytics.team.privateGroups": "Private Kanäle", "analytics.team.publicChannels": "Öffentliche Kanäle", "analytics.team.recentUsers": "Zuletzt aktive Benutzer", diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index 6061ac68d6..96ba84bfa0 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -265,10 +265,9 @@ "admin.billing.history.allPaymentsShowHere": "All of your invoices will be shown here", "admin.billing.history.date": "Date", "admin.billing.history.description": "Description", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} metered users, {fullUsers} users at full rate, {partialUsers} users with partial charges", - "admin.billing.history.fractionalUsers": "{fractionalUsers} users", + "admin.billing.history.fractionalSeats": "{fractionalUsers} seats", "admin.billing.history.noBillingHistory": "In the future, this is where your billing history will show.", - "admin.billing.history.onPremUsers": "{num} users", + "admin.billing.history.onPremSeats": "{num} seats", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} of {totalRecords}", "admin.billing.history.paid": "Paid", "admin.billing.history.paymentFailed": "Payment failed", @@ -278,7 +277,7 @@ "admin.billing.history.title": "Billing History", "admin.billing.history.total": "Total", "admin.billing.history.transactions": "Transactions", - "admin.billing.history.usersAndRates": "{fullUsers} users at full rate, {partialUsers} users with partial charges", + "admin.billing.history.seatsAndRates": "{fullUsers} seats at full rate, {partialUsers} seats with partial charges", "admin.billing.payment_info_display.allCardsAccepted": "All major credit cards are accepted.", "admin.billing.payment_info_display.noPaymentInfo": "There are currently no credit cards on file.", "admin.billing.payment_info_display.savedPaymentDetails": "Your saved payment details", @@ -2595,7 +2594,7 @@ "analytics.team.activeUsers": "Active Users With Posts", "analytics.team.newlyCreated": "Newly Created Users", "analytics.team.noTeams": "This server has no teams for which to view statistics.", - "analytics.team.overageUsersSeats": "This exceeds total paid users", + "analytics.team.overageUsersSeats": "This exceeds total paid seats", "analytics.team.privateGroups": "Private Channels", "analytics.team.publicChannels": "Public Channels", "analytics.team.recentUsers": "Recent Active Users", diff --git a/webapp/channels/src/i18n/en_AU.json b/webapp/channels/src/i18n/en_AU.json index b8c9128aae..d83fe1e0e9 100644 --- a/webapp/channels/src/i18n/en_AU.json +++ b/webapp/channels/src/i18n/en_AU.json @@ -265,10 +265,10 @@ "admin.billing.history.allPaymentsShowHere": "All of your invoices will be shown here", "admin.billing.history.date": "Date", "admin.billing.history.description": "Description", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} metered users, {fullUsers} users at full rate, {partialUsers} users with partial charges", - "admin.billing.history.fractionalUsers": "{fractionalUsers} users", + "admin.billing.history.fractionalAndRatedSeats": "{fractionalSeats} metered seats, {fullSeats} seats at full rate, {partialSeats} seats with partial charges", + "admin.billing.history.fractionalSeats": "{fractionalUsers} seats", "admin.billing.history.noBillingHistory": "In the future, this is where your billing history will show.", - "admin.billing.history.onPremUsers": "{num} users", + "admin.billing.history.onPremSeats": "{num} seats", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} of {totalRecords}", "admin.billing.history.paid": "Paid", "admin.billing.history.paymentFailed": "Payment failed", @@ -278,7 +278,7 @@ "admin.billing.history.title": "Billing History", "admin.billing.history.total": "Total", "admin.billing.history.transactions": "Transactions", - "admin.billing.history.usersAndRates": "{fullUsers} users at full rate, {partialUsers} users with partial charges", + "admin.billing.history.seatsAndRates": "{fullSeats} seats at full rate, {partialSeats} seats with partial charges", "admin.billing.payment_info.add": "Add a Credit Card", "admin.billing.payment_info.billingAddress": "Billing Address", "admin.billing.payment_info.cardBrandAndDigits": "{brand} ending in {digits}", @@ -2592,7 +2592,7 @@ "analytics.team.activeUsers": "Active Users With Posts", "analytics.team.newlyCreated": "Newly Created Users", "analytics.team.noTeams": "This server has no teams for which to view statistics.", - "analytics.team.overageUsersSeats": "This exceeds total paid users", + "analytics.team.overageUsersSeats": "This exceeds total paid seats", "analytics.team.privateGroups": "Private Channels", "analytics.team.publicChannels": "Public Channels", "analytics.team.recentUsers": "Recent Active Users", diff --git a/webapp/channels/src/i18n/es.json b/webapp/channels/src/i18n/es.json index 2730763abe..29c0bb0a86 100644 --- a/webapp/channels/src/i18n/es.json +++ b/webapp/channels/src/i18n/es.json @@ -259,8 +259,6 @@ "admin.billing.history.allPaymentsShowHere": "Todos sus pagos mensuales se mostrarán aquí", "admin.billing.history.date": "Fecha", "admin.billing.history.description": "Descripción", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} usuarios medidos, {fullUsers} usuarios con tarifa completa, {partialUsers} usuarios con tarifa parcial", - "admin.billing.history.fractionalUsers": "{fractionalUsers} usuarios", "admin.billing.history.noBillingHistory": "En el futuro, aquí es donde se mostrará su historial de facturación.", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} de {totalRecords}", "admin.billing.history.paid": "Pagado", @@ -271,7 +269,6 @@ "admin.billing.history.title": "Historial de facturación", "admin.billing.history.total": "Total", "admin.billing.history.transactions": "Transacciones", - "admin.billing.history.usersAndRates": "{fullUsers} usuarios a tarifa completa, {partialUsers} usuarios con cargos parciales", "admin.billing.payment_info.add": "Agregar tarjeta de crédito", "admin.billing.payment_info.billingAddress": "Dirección de Facturación", "admin.billing.payment_info.cardBrandAndDigits": "{brand} terminada en {digits}", diff --git a/webapp/channels/src/i18n/fa.json b/webapp/channels/src/i18n/fa.json index 86af91132c..784302be1a 100644 --- a/webapp/channels/src/i18n/fa.json +++ b/webapp/channels/src/i18n/fa.json @@ -252,9 +252,7 @@ "admin.billing.history.allPaymentsShowHere": "همه پرداخت‌های ماهانه شما در اینجا نشان داده می‌شود", "admin.billing.history.date": "تاریخ", "admin.billing.history.description": "شرح", - "admin.billing.history.fractionalUsers": "کاربران {fractionalUsers}", "admin.billing.history.noBillingHistory": "در آینده، این جایی است که سابقه صورتحساب شما نشان داده خواهد شد.", - "admin.billing.history.onPremUsers": "{num} کاربر", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} از {totalRecords}", "admin.billing.history.paid": "پرداخت شده", "admin.billing.history.paymentFailed": "پرداخت ناموفق", diff --git a/webapp/channels/src/i18n/fr.json b/webapp/channels/src/i18n/fr.json index 0b4cc9471e..51356da7f1 100644 --- a/webapp/channels/src/i18n/fr.json +++ b/webapp/channels/src/i18n/fr.json @@ -258,10 +258,7 @@ "admin.billing.history.allPaymentsShowHere": "Tous vos paiements mensuels apparaîtront ici", "admin.billing.history.date": "Date", "admin.billing.history.description": "Description", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} utilisateurs mesurés, {fullUsers} utilisateurs à plein tarif, {partialUsers} utilisateurs avec des frais partiels", - "admin.billing.history.fractionalUsers": "{fractionalUsers} utilisateurs", "admin.billing.history.noBillingHistory": "À l'avenir, c'est ici que votre historique de facturation apparaîtra.", - "admin.billing.history.onPremUsers": "{num} utilisateurs", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} de {totalRecords}", "admin.billing.history.paid": "Payé", "admin.billing.history.paymentFailed": "Échec du paiement", @@ -271,7 +268,6 @@ "admin.billing.history.title": "Historique de facturation", "admin.billing.history.total": "Total", "admin.billing.history.transactions": "Transactions", - "admin.billing.history.usersAndRates": "{fullUsers} utilisateurs à tarif plein, {partielsUsers} utilisateurs à tarif réduit", "admin.billing.payment_info.add": "Ajouter une carte de crédit", "admin.billing.payment_info.billingAddress": "Adresse de facturation", "admin.billing.payment_info.cardBrandAndDigits": "{marque} se terminant par {chiffres}", diff --git a/webapp/channels/src/i18n/hu.json b/webapp/channels/src/i18n/hu.json index aa0bfebfb6..be4db12af4 100644 --- a/webapp/channels/src/i18n/hu.json +++ b/webapp/channels/src/i18n/hu.json @@ -251,8 +251,6 @@ "admin.billing.history.allPaymentsShowHere": "Minden havi befizetése itt jelenik meg", "admin.billing.history.date": "Dátum", "admin.billing.history.description": "Leírás", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} mért felhasználó, {fullUsers} felhasználó teljes díjszabással, {partialUsers} felhasználó részleges díjszabással", - "admin.billing.history.fractionalUsers": "{fractionalUsers} felhasználó", "admin.billing.history.noBillingHistory": "A jövőben itt fognak megjelenni a számlázási előzményei.", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} / {totalRecords}", "admin.billing.history.paid": "Fizetett", @@ -263,7 +261,6 @@ "admin.billing.history.title": "Számlázási előzmények", "admin.billing.history.total": "Összesen", "admin.billing.history.transactions": "Tranzakciók", - "admin.billing.history.usersAndRates": "{fullUsers} felhasználó teljes áron, {partialUsers} felhasználó részleges díjakkal", "admin.billing.payment_info.add": "Hitelkártya hozzáadása", "admin.billing.payment_info.billingAddress": "Számlázási cím", "admin.billing.payment_info.cardBrandAndDigits": "{brand} {digits} végződéssel", diff --git a/webapp/channels/src/i18n/it.json b/webapp/channels/src/i18n/it.json index b64ecd9cd4..83ad4ec4d0 100644 --- a/webapp/channels/src/i18n/it.json +++ b/webapp/channels/src/i18n/it.json @@ -250,8 +250,6 @@ "admin.billing.history.allPaymentsShowHere": "Qui vengono mostrati tutti i pagamenti mensili", "admin.billing.history.date": "Data", "admin.billing.history.description": "Descrizione", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} utenti misurati, {fullUsers} utenti a tariffa piena, {partialUsers} utenti con addebiti parziali", - "admin.billing.history.fractionalUsers": "{fractionalUsers} utenti", "admin.billing.history.noBillingHistory": "Prossimamente in questa sezione verrà mostrato lo storico delle fatturazioni.", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} di {totalRecords}", "admin.billing.history.paid": "Pagato", @@ -262,7 +260,6 @@ "admin.billing.history.title": "Storico delle fatture", "admin.billing.history.total": "Totale", "admin.billing.history.transactions": "Transazioni", - "admin.billing.history.usersAndRates": "{fullUsers} utenti a tariffa piena, {partialUsers} utenti con addebiti parziali", "admin.billing.payment_info.add": "Aggiungi una carta di credito", "admin.billing.payment_info.billingAddress": "Indirizzo di pagamento", "admin.billing.payment_info.cardBrandAndDigits": "{brand} finisce in {digits}", diff --git a/webapp/channels/src/i18n/ja.json b/webapp/channels/src/i18n/ja.json index f2804b5e0d..30838c9df8 100644 --- a/webapp/channels/src/i18n/ja.json +++ b/webapp/channels/src/i18n/ja.json @@ -265,10 +265,7 @@ "admin.billing.history.allPaymentsShowHere": "すべての請求書がここに表示されます", "admin.billing.history.date": "日付", "admin.billing.history.description": "説明", - "admin.billing.history.fractionalAndRatedUsers": "従量制ユーザー: {fractionalUsers}名、正規料金のユーザー: {fullUsers}名、部分料金のユーザー: {partialUsers}名", - "admin.billing.history.fractionalUsers": "{fractionalUsers}ユーザー", "admin.billing.history.noBillingHistory": "今後、ここに請求履歴が表示されます。", - "admin.billing.history.onPremUsers": "{num} ユーザー", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} of {totalRecords}", "admin.billing.history.paid": "支払い済", "admin.billing.history.paymentFailed": "支払い失敗", @@ -278,7 +275,6 @@ "admin.billing.history.title": "請求履歴", "admin.billing.history.total": "合計", "admin.billing.history.transactions": "処理", - "admin.billing.history.usersAndRates": "{fullUsers} ユーザーは全額課金、{partialUsers} ユーザーは一部課金", "admin.billing.payment_info.add": "クレジットカード情報を追加する", "admin.billing.payment_info.billingAddress": "請求先住所", "admin.billing.payment_info.cardBrandAndDigits": "末尾が {digits} の {brand}", @@ -2595,7 +2591,6 @@ "analytics.team.activeUsers": "投稿実績のあるアクティブユーザー", "analytics.team.newlyCreated": "新規作成ユーザー数", "analytics.team.noTeams": "このサーバーには統計情報を閲覧可能なチームが存在しません。", - "analytics.team.overageUsersSeats": "有償ユーザー数を超えています", "analytics.team.privateGroups": "非公開チャンネル", "analytics.team.publicChannels": "公開チャンネル", "analytics.team.recentUsers": "最近のアクティブユーザー数", diff --git a/webapp/channels/src/i18n/ko.json b/webapp/channels/src/i18n/ko.json index a73022b548..b2ad76db44 100644 --- a/webapp/channels/src/i18n/ko.json +++ b/webapp/channels/src/i18n/ko.json @@ -258,10 +258,7 @@ "admin.billing.history.allPaymentsShowHere": "모든 월별 결제 금액이 여기에 표시됩니다", "admin.billing.history.date": "날짜", "admin.billing.history.description": "설명", - "admin.billing.history.fractionalAndRatedUsers": "종량제 사용자: {fractionalUsers}명, 정규 요금 사용자: {fullUsers}명, 부분 요금 사용자: {partialUsers}명", - "admin.billing.history.fractionalUsers": "{fractionalUsers} 사용자", "admin.billing.history.noBillingHistory": "앞으로, 이곳에 결제내역이 표시됩니다.", - "admin.billing.history.onPremUsers": "{num}명의 사용자", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} 의 {totalRecords}", "admin.billing.history.paid": "구매 완료", "admin.billing.history.paymentFailed": "결제 실패", @@ -271,7 +268,6 @@ "admin.billing.history.title": "결제 내역", "admin.billing.history.total": "합계", "admin.billing.history.transactions": "거래 내역", - "admin.billing.history.usersAndRates": "전체 요금의 사용자 {fullUsers}명, 부분 요금의 사용자 {partialUsers}명", "admin.billing.payment_info.add": "신용 카드 추가", "admin.billing.payment_info.billingAddress": "청구 주소", "admin.billing.payment_info.cardBrandAndDigits": "{digits}로 끝나는 {brand}카드", diff --git a/webapp/channels/src/i18n/nl.json b/webapp/channels/src/i18n/nl.json index d643a8523c..f3a8aed7c4 100644 --- a/webapp/channels/src/i18n/nl.json +++ b/webapp/channels/src/i18n/nl.json @@ -265,10 +265,7 @@ "admin.billing.history.allPaymentsShowHere": "Een overzicht van al je facturen zal hier worden weergegeven", "admin.billing.history.date": "Datum", "admin.billing.history.description": "Omschrijving", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} gebruikers met beperkt gebruik, {fullUsers} gebruikers tegen vol tarief, {partialUsers} gebruikers met gedeeltelijke kosten", - "admin.billing.history.fractionalUsers": "{fractionalUsers} gebruikers", "admin.billing.history.noBillingHistory": "In de toekomst zal hier je facturatiegeschiedenis getoond worden.", - "admin.billing.history.onPremUsers": "{num} gebruikers", "admin.billing.history.pageInfo": "{startRecord}-{endRecord} van {totalRecords}", "admin.billing.history.paid": "Betaald", "admin.billing.history.paymentFailed": "Betaling is mislukt", @@ -278,7 +275,6 @@ "admin.billing.history.title": "Facturatiegeschiedenis", "admin.billing.history.total": "Totaal", "admin.billing.history.transactions": "Transacties", - "admin.billing.history.usersAndRates": "{fullUsers} gebruikers aan een volledig tarief, {partialUsers} gebruikers met verminderd tarief", "admin.billing.payment_info.add": "Voeg een kredietkaart toe", "admin.billing.payment_info.billingAddress": "Facturatieadres", "admin.billing.payment_info.cardBrandAndDigits": "{brand} eindigend op {digits}", @@ -2593,7 +2589,6 @@ "analytics.team.activeUsers": "Actieve gebruikers met berichten", "analytics.team.newlyCreated": "Nieuw gemaakte gebruikers", "analytics.team.noTeams": "Deze server heeft geen teams om statistische gegevens te bekijken.", - "analytics.team.overageUsersSeats": "Dit overtreft het totale aantal betaalde gebruikers", "analytics.team.privateGroups": "Privé-kanalen", "analytics.team.publicChannels": "Publieke kanalen", "analytics.team.recentUsers": "Recent actieve gebruikers", diff --git a/webapp/channels/src/i18n/pl.json b/webapp/channels/src/i18n/pl.json index be3310220a..c4784f3d61 100644 --- a/webapp/channels/src/i18n/pl.json +++ b/webapp/channels/src/i18n/pl.json @@ -265,10 +265,7 @@ "admin.billing.history.allPaymentsShowHere": "Wszystkie Twoje faktury będą widoczne tutaj", "admin.billing.history.date": "Data", "admin.billing.history.description": "Opis", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} użytkownicy z opłatą licznikową, {fullUsers} użytkownicy z pełną stawką, {partialUsers} użytkownicy z opłatą częściową", - "admin.billing.history.fractionalUsers": "Użytkownicy {fractionalUsers}", "admin.billing.history.noBillingHistory": "W przyszłości w tym miejscu będzie widoczna historia Twoich rozliczeń.", - "admin.billing.history.onPremUsers": "{num} użytkowników", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} z {totalRecords}", "admin.billing.history.paid": "Płatne", "admin.billing.history.paymentFailed": "Płatność nie powiodła się", @@ -278,7 +275,6 @@ "admin.billing.history.title": "Historia rozliczeń", "admin.billing.history.total": "Ogółem", "admin.billing.history.transactions": "Transakcje", - "admin.billing.history.usersAndRates": "{fullUsers} użytkownicy z pełną stawką, {partialUsers} użytkownicy z częściową opłatą", "admin.billing.payment_info.add": "Dodaj kartę kredytową", "admin.billing.payment_info.billingAddress": "Adres rozliczeniowy", "admin.billing.payment_info.cardBrandAndDigits": "{brand} kończący na {digits}", @@ -2595,7 +2591,6 @@ "analytics.team.activeUsers": "Aktywni użytkownicy z wiadomościami", "analytics.team.newlyCreated": "Nowi użytkownicy", "analytics.team.noTeams": "Nie ma na tym serwerze zespołów dla których można zobaczyć statystyki.", - "analytics.team.overageUsersSeats": "To przekracza łączną liczbę płatnych użytkowników", "analytics.team.privateGroups": "Kanały prywatne", "analytics.team.publicChannels": "Kanały publiczne", "analytics.team.recentUsers": "Ostatnio Aktywni Użytkownicy", diff --git a/webapp/channels/src/i18n/pt-BR.json b/webapp/channels/src/i18n/pt-BR.json index 7c727fa2d3..bf21ed7ea1 100644 --- a/webapp/channels/src/i18n/pt-BR.json +++ b/webapp/channels/src/i18n/pt-BR.json @@ -245,8 +245,6 @@ "admin.billing.history.allPaymentsShowHere": "Todos os seus pagamentos mensais serão exibidos aqui", "admin.billing.history.date": "Data", "admin.billing.history.description": "Descrição", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} usuários medidos, {fullUsers} usuários com taxa total, {partialUsers} usuários com cobranças parciais", - "admin.billing.history.fractionalUsers": "{fractionalUsers} usuários", "admin.billing.history.noBillingHistory": "No futuro, é aqui que seu histórico de faturamento será exibido.", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} de {totalRecords}", "admin.billing.history.paid": "Pago", @@ -257,7 +255,6 @@ "admin.billing.history.title": "Histórico de Pagamento", "admin.billing.history.total": "Total", "admin.billing.history.transactions": "Transações", - "admin.billing.history.usersAndRates": "{fullUsers} usuários com taxa total, {partialUsers} usuários com taxas parciais", "admin.billing.payment_info.add": "Adicionar um Cartão de Crédito", "admin.billing.payment_info.billingAddress": "Endereço de Cobrança", "admin.billing.payment_info.cardBrandAndDigits": "{brand} terminando em {digits}", diff --git a/webapp/channels/src/i18n/ro.json b/webapp/channels/src/i18n/ro.json index 1f71d191a4..19769ccd8d 100644 --- a/webapp/channels/src/i18n/ro.json +++ b/webapp/channels/src/i18n/ro.json @@ -240,7 +240,6 @@ "admin.billing.history.title": "Istoricul facturării", "admin.billing.history.total": "Total", "admin.billing.history.transactions": "Tranzacții", - "admin.billing.history.usersAndRates": "{fullUsers} utilizatori la tarif complet, {partialUsers} utilizatori cu taxe parțiale", "admin.billing.payment_info.add": "Adăugați un card de credit", "admin.billing.payment_info.billingAddress": "Adresa De Facturare", "admin.billing.payment_info.cardBrandAndDigits": "{brand} care se termină cu {digits}", diff --git a/webapp/channels/src/i18n/ru.json b/webapp/channels/src/i18n/ru.json index 6490e1b2b9..ee870bc6a2 100644 --- a/webapp/channels/src/i18n/ru.json +++ b/webapp/channels/src/i18n/ru.json @@ -265,10 +265,7 @@ "admin.billing.history.allPaymentsShowHere": "Здесь будут отображаться все ваши счета-фактуры", "admin.billing.history.date": "Дата", "admin.billing.history.description": "Описание", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} подсчитанных пользователей, {fullUsers} пользователей с полной ставкой, {partialUsers} пользователей с частичной оплатой", - "admin.billing.history.fractionalUsers": "{fractionalUsers} пользователей", "admin.billing.history.noBillingHistory": "В будущем здесь будет отображаться история ваших счетов.", - "admin.billing.history.onPremUsers": "{num} пользователи", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} из {totalRecords}", "admin.billing.history.paid": "Оплачен", "admin.billing.history.paymentFailed": "Платеж не прошел", @@ -278,7 +275,6 @@ "admin.billing.history.title": "История счетов", "admin.billing.history.total": "Всего", "admin.billing.history.transactions": "Транзакции", - "admin.billing.history.usersAndRates": "{fullUsers} пользователи на полную ставку, {partialUsers} пользователи с частичной оплатой", "admin.billing.payment_info.add": "Добавить кредитную карту", "admin.billing.payment_info.billingAddress": "Адрес для выставления счета", "admin.billing.payment_info.cardBrandAndDigits": "{brand} истекает {digits}", @@ -2595,7 +2591,6 @@ "analytics.team.activeUsers": "Активные пользователи с сообщениями", "analytics.team.newlyCreated": "Новые пользователи", "analytics.team.noTeams": "На этом сервере нет команд для которых можно просмотреть статистику.", - "analytics.team.overageUsersSeats": "Это превышает общее количество платных пользователей", "analytics.team.privateGroups": "Приватные каналы", "analytics.team.publicChannels": "Публичные каналы", "analytics.team.recentUsers": "Недавние активные пользователи", diff --git a/webapp/channels/src/i18n/sv.json b/webapp/channels/src/i18n/sv.json index c52f96f039..6f2c7bc76c 100644 --- a/webapp/channels/src/i18n/sv.json +++ b/webapp/channels/src/i18n/sv.json @@ -265,10 +265,7 @@ "admin.billing.history.allPaymentsShowHere": "Alla fakturor kommer visas här", "admin.billing.history.date": "Datum", "admin.billing.history.description": "Beskrivning", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} användare som mäts, {fullUsers} användare med full kostnad, {partialUsers} användare med delkostnader", - "admin.billing.history.fractionalUsers": "{fractionalUsers} användare", "admin.billing.history.noBillingHistory": "I framtiden kommer din fakturahistorik visas här.", - "admin.billing.history.onPremUsers": "{num} användare", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} av {totalRecords}", "admin.billing.history.paid": "Betald", "admin.billing.history.paymentFailed": "Betalning misslyckades", @@ -278,7 +275,6 @@ "admin.billing.history.title": "Betalhistorik", "admin.billing.history.total": "Summa", "admin.billing.history.transactions": "Transaktioner", - "admin.billing.history.usersAndRates": "{fullUsers} användare till full kostnad, {partialUsers} användare med rabatterad kostnad", "admin.billing.payment_info.add": "Lägg till betalkort", "admin.billing.payment_info.billingAddress": "Fakturaadress", "admin.billing.payment_info.cardBrandAndDigits": "{brand} tar slut om {digits}", @@ -2595,7 +2591,6 @@ "analytics.team.activeUsers": "Aktiva användare med meddelanden", "analytics.team.newlyCreated": "Nyligen skapade användare", "analytics.team.noTeams": "Servern har inga team som kan visa statistik.", - "analytics.team.overageUsersSeats": "Detta överstiger det totala antalet betalande användare", "analytics.team.privateGroups": "Privat kanal", "analytics.team.publicChannels": "Publika kanaler", "analytics.team.recentUsers": "Nyligen aktiva användare", diff --git a/webapp/channels/src/i18n/tr.json b/webapp/channels/src/i18n/tr.json index 588a76ce27..d61c34f273 100644 --- a/webapp/channels/src/i18n/tr.json +++ b/webapp/channels/src/i18n/tr.json @@ -258,10 +258,7 @@ "admin.billing.history.allPaymentsShowHere": "Tüm faturalanınız burada görüntülenir", "admin.billing.history.date": "Tarih", "admin.billing.history.description": "Açıklama", - "admin.billing.history.fractionalAndRatedUsers": "Sınırlı {fractionalUsers} kullanıcı, tam ücretli {fullUsers} kullanıcı, kısmi ücretli {partialUsers} kullanıcı", - "admin.billing.history.fractionalUsers": "{fractionalUsers} kullanıcı", "admin.billing.history.noBillingHistory": "Gelecekte, fatura geçmişiniz burada görüntülenecek.", - "admin.billing.history.onPremUsers": "{num} kullanıcı", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} / {totalRecords}", "admin.billing.history.paid": "Ödendi", "admin.billing.history.paymentFailed": "Ödenmedi", @@ -271,7 +268,6 @@ "admin.billing.history.title": "Faturalama geçmişi", "admin.billing.history.total": "Toplam", "admin.billing.history.transactions": "İşlemler", - "admin.billing.history.usersAndRates": "{fullUsers} kullanıcı için tam ödeme, {partialUsers} kullanıcı için kısmi ödeme", "admin.billing.payment_info.add": "Kredi kartı ekle", "admin.billing.payment_info.billingAddress": "Fatura adresi", "admin.billing.payment_info.cardBrandAndDigits": "{brand} {digits} ile biten", @@ -2553,7 +2549,6 @@ "analytics.team.activeUsers": "İleti yazmış etkin kullanıcılar", "analytics.team.newlyCreated": "Yeni eklenen kullanıcılar", "analytics.team.noTeams": "Bu sunucuda istatistikleri görüntülenebilecek bir takım yok.", - "analytics.team.overageUsersSeats": "Bu ücreti ödenmiş kullanıcı sayısını aşıyor", "analytics.team.privateGroups": "Özel kanallar", "analytics.team.publicChannels": "Herkese açık kanallar", "analytics.team.recentUsers": "Son etkin kullanıcılar", diff --git a/webapp/channels/src/i18n/zh-CN.json b/webapp/channels/src/i18n/zh-CN.json index 2db89a3255..726b018637 100644 --- a/webapp/channels/src/i18n/zh-CN.json +++ b/webapp/channels/src/i18n/zh-CN.json @@ -265,10 +265,7 @@ "admin.billing.history.allPaymentsShowHere": "您所有的发票都将显示在这里", "admin.billing.history.date": "日期", "admin.billing.history.description": "描述", - "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} 计量用户, {fullUsers} 全款用户, {partialUsers} 部分收费用户", - "admin.billing.history.fractionalUsers": "{fractionalUsers} 位用户", "admin.billing.history.noBillingHistory": "这是您的帐单记录显示的地方。", - "admin.billing.history.onPremUsers": "{num} 用户", "admin.billing.history.pageInfo": "{startRecord} - {endRecord},共 {totalRecords} 个", "admin.billing.history.paid": "已支付", "admin.billing.history.paymentFailed": "支付失败", @@ -278,7 +275,6 @@ "admin.billing.history.title": "帐单记录", "admin.billing.history.total": "总计", "admin.billing.history.transactions": "交易", - "admin.billing.history.usersAndRates": "{fullUsers} 位用户全额收费,{partialUsers} 位用户收取部分费用", "admin.billing.payment_info.add": "添加信用卡", "admin.billing.payment_info.billingAddress": "帐单地址", "admin.billing.payment_info.cardBrandAndDigits": "{brand} 以 {digits} 结尾", From 25035a72c4de3b6e59bbae100df24920ec013a7b Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Thu, 30 Mar 2023 16:33:39 -0400 Subject: [PATCH 03/58] update a few more places with seemingly incorrect useage of 'users'. --- .../cloud/billing/yearly_subscription_spec.js | 2 +- .../self-hosted/self_hosted_purchase_spec.ts | 2 +- .../billing/billing_summary/billing_summary.tsx | 12 ++++++------ .../license_settings/modals/upload_license_modal.tsx | 2 +- .../src/components/seats_calculator/index.tsx | 6 +++--- .../self_hosted_purchase_modal/index.test.tsx | 2 +- webapp/channels/src/i18n/bg.json | 2 -- webapp/channels/src/i18n/de.json | 5 ----- webapp/channels/src/i18n/en.json | 10 +++++----- webapp/channels/src/i18n/en_AU.json | 10 +++++----- webapp/channels/src/i18n/es.json | 3 --- webapp/channels/src/i18n/fa.json | 2 -- webapp/channels/src/i18n/fr.json | 3 --- webapp/channels/src/i18n/hu.json | 3 --- webapp/channels/src/i18n/ja.json | 5 ----- webapp/channels/src/i18n/ko.json | 2 -- webapp/channels/src/i18n/nl.json | 5 ----- webapp/channels/src/i18n/pl.json | 5 ----- webapp/channels/src/i18n/pt-BR.json | 2 -- webapp/channels/src/i18n/ro.json | 2 -- webapp/channels/src/i18n/ru.json | 5 ----- webapp/channels/src/i18n/sv.json | 5 ----- webapp/channels/src/i18n/tr.json | 5 ----- webapp/channels/src/i18n/zh-CN.json | 2 -- 24 files changed, 23 insertions(+), 79 deletions(-) diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/cloud/billing/yearly_subscription_spec.js b/e2e-tests/cypress/tests/integration/channels/enterprise/cloud/billing/yearly_subscription_spec.js index 0eacc1350c..5351459903 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/cloud/billing/yearly_subscription_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/cloud/billing/yearly_subscription_spec.js @@ -147,7 +147,7 @@ describe('System Console - Subscriptions section', () => { // * Ensure that the yearly, monthly, and yearly saving prices match the new user seats value entered checkValues(lessThanUserCount); - cy.get('.RHS').get('.Input___customMessage').contains(`Your workspace currently has ${count} users`); + cy.get('.RHS').get('.Input___customMessage').contains(`Your workspace currently has ${count} active users`); // * Check that Upgrade button is not enabled cy.get('.RHS').find('button').should('be.disabled'); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/self-hosted/self_hosted_purchase_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/self-hosted/self_hosted_purchase_spec.ts index a21f5994b1..cbbe859a82 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/self-hosted/self_hosted_purchase_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/self-hosted/self_hosted_purchase_spec.ts @@ -340,7 +340,7 @@ describe('Self hosted Purchase', () => { getCurrentUsers().then((currentUsers) => { // * Verify form can not be submitted - cy.contains(`Your workspace currently has ${currentUsers} users`).should('not.be.enabled'); + cy.contains(`Your workspace currently has ${currentUsers} active users`).should('not.be.enabled'); cy.contains('Upgrade').should('not.be.enabled'); // # Fill form the same number of seats as current users diff --git a/webapp/channels/src/components/admin_console/billing/billing_summary/billing_summary.tsx b/webapp/channels/src/components/admin_console/billing/billing_summary/billing_summary.tsx index 14c9f85791..5a3c40872a 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_summary/billing_summary.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_summary/billing_summary.tsx @@ -226,9 +226,9 @@ export const InvoiceInfo = ({invoice, product, fullCharges, partialCharges, hasM currency='USD' /> )} @@ -309,9 +309,9 @@ export const InvoiceInfo = ({invoice, product, fullCharges, partialCharges, hasM >
diff --git a/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx b/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx index 7d16824535..634b030724 100644 --- a/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx @@ -260,7 +260,7 @@ const UploadLicenseModal = (props: Props): JSX.Element | null => {
, }} @@ -88,7 +88,7 @@ function validateSeats(seats: string, annualPricePerSeat: number, minSeats: numb {errorPrefix} , }} diff --git a/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx b/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx index 3ccbb74ce2..81437b3d7a 100644 --- a/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx +++ b/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx @@ -255,7 +255,7 @@ describe('SelfHostedPurchaseModal', () => { // check title, and some of the most prominent details and secondary actions screen.getByText('Provide your payment details'); screen.getByText('Contact Sales'); - screen.getByText('USD per user/month', {exact: false}); + screen.getByText('USD per seat/month', {exact: false}); screen.getByText('billed annually', {exact: false}); screen.getByText(productName); screen.getByText('You will be billed today. Your license will be applied automatically', {exact: false}); diff --git a/webapp/channels/src/i18n/bg.json b/webapp/channels/src/i18n/bg.json index 6aabdc38d5..b8a5507bd4 100644 --- a/webapp/channels/src/i18n/bg.json +++ b/webapp/channels/src/i18n/bg.json @@ -332,8 +332,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Такси", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Последна фактура", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Общо", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} потребителя", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} потребителя", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "Какво представляват частичните такси?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Потребителите, които не са били активирани през цялото време на месеца, се таксуват с пропорционална месечна ставка.", "admin.billing.subscriptions.billing_summary.noBillingHistory.description": "В бъдеще това е мястото, където ще се показва обобщение на вашите последни таксувания.", diff --git a/webapp/channels/src/i18n/de.json b/webapp/channels/src/i18n/de.json index 56c0a379f1..5a34d538a1 100644 --- a/webapp/channels/src/i18n/de.json +++ b/webapp/channels/src/i18n/de.json @@ -412,8 +412,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Steuern", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Letzte Rechnung", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Total", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} Benutzer", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} Benutzer", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "Rechnung ansehen", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "Was sind teilweise verrechnete Gebühren?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Benutzer, die nicht für die volle Dauer des Monats freigeschaltet waren, werden mit einem anteiligen Monatsrate berechnet.", @@ -1355,7 +1353,6 @@ "admin.license.upload-modal.file": "Datei", "admin.license.upload-modal.subtitle": "Lade eine Lizenzschlüssel für die Mattermost Enterprise Edition hoch, um den Server zu aktualisieren. ", "admin.license.upload-modal.successfulUpgrade": "Erfolgreiche Aktualisierung!", - "admin.license.upload-modal.successfulUpgradeText": "Du hast den {skuName} Plan für {licensedUsersNum, number} Benutzer aktualisiert. Diese Änderung ist aktiv vom {startsAt} bis zum {expiresAt}. ", "admin.license.upload-modal.title": "Lizenzschlüssel hochladen", "admin.license.uploadFile": "Datei hochladen", "admin.license.warn.renew": "Erneuern", @@ -4708,8 +4705,6 @@ "self_hosted_signup.cta": "Aktualisieren", "self_hosted_signup.disclaimer": "Ich habe die Enterprise Edition Abonnementbedingungen gelesen und stimme ihnen zu.", "self_hosted_signup.error_invalid_number": "Gib eine gültige Anzahl von Plätzen ein", - "self_hosted_signup.error_max_seats": " Der Lizenzkauf unterstützt nur Käufe bis zu {num} Benutzern", - "self_hosted_signup.error_min_seats": "Dein Arbeitsbereich hat derzeit {num} Benutzer", "self_hosted_signup.failed_export.subtitle": "Wir werden die Dinge von unserer Seite aus überprüfen und uns innerhalb von 3 Tagen bei dir melden, sobald deine Lizenz genehmigt ist. In der Zwischenzeit kannst du gerne die kostenlose Version unseres Produkts weiter nutzen.", "self_hosted_signup.failed_export.title": "Deine Transaktion wird überprüft", "self_hosted_signup.license_applied": "Deine {planName} Lizenz wurde jetzt angewendet. {planName} Funktionen sind jetzt verfügbar und einsatzbereit.", diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index 96ba84bfa0..35c493f09b 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -415,8 +415,8 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Taxes", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Last Invoice", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Total", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} users", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} users", + "admin.billing.subscriptions.billing_summary.lastInvoice.seatCount": " x {seats} seats", + "admin.billing.subscriptions.billing_summary.lastInvoice.seatCountPartial": "{seats} seats", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "View Invoice", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "What are partial charges?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Users who have not been enabled for the full duration of the month are charged at a prorated monthly rate.", @@ -1358,7 +1358,7 @@ "admin.license.upload-modal.file": "File", "admin.license.upload-modal.subtitle": "Upload a license key for Mattermost Enterprise Edition to upgrade this server. ", "admin.license.upload-modal.successfulUpgrade": "Successful Upgrade!", - "admin.license.upload-modal.successfulUpgradeText": "You have upgraded to the {skuName} plan for {licensedUsersNum, number} users. This is effective from {startsAt} until {expiresAt}. ", + "admin.license.upload-modal.successfulUpgradeText": "You have upgraded to the {skuName} plan for {licensedUsersNum, number} seats. This is effective from {startsAt} until {expiresAt}. ", "admin.license.upload-modal.title": "Upload a License Key", "admin.license.uploadFile": "Upload File", "admin.license.warn.renew": "Renew", @@ -4706,8 +4706,8 @@ "self_hosted_signup.cta": "Upgrade", "self_hosted_signup.disclaimer": "I have read and agree to the Enterprise Edition Subscription Terms", "self_hosted_signup.error_invalid_number": "Enter a valid number of seats", - "self_hosted_signup.error_max_seats": " license purchase only supports purchases up to {num} users", - "self_hosted_signup.error_min_seats": "Your workspace currently has {num} users", + "self_hosted_signup.error_max_seats": " license purchase only supports purchases up to {num} seats", + "self_hosted_signup.error_min_users": "Your workspace currently has {num} active users", "self_hosted_signup.failed_export.subtitle": "We will check things on our side and get back to you within 3 days once your license is approved. In the meantime, please feel free to continue using the free version of our product.", "self_hosted_signup.failed_export.title": "Your transaction is being reviewed", "self_hosted_signup.license_applied": "Your {planName} license has now been applied. {planName} features are now available and ready to use.", diff --git a/webapp/channels/src/i18n/en_AU.json b/webapp/channels/src/i18n/en_AU.json index d83fe1e0e9..16b3a1b373 100644 --- a/webapp/channels/src/i18n/en_AU.json +++ b/webapp/channels/src/i18n/en_AU.json @@ -415,8 +415,8 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Taxes", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Last Invoice", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Total", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} users", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} users", + "admin.billing.subscriptions.billing_summary.lastInvoice.seatCount": " x {seats} seats", + "admin.billing.subscriptions.billing_summary.lastInvoice.seatCountPartial": "{seats} seats", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "View Invoice", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "What are partial charges?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Users who have not been enabled for the full duration of the month are charged at a prorated monthly rate.", @@ -1357,7 +1357,7 @@ "admin.license.upload-modal.file": "File", "admin.license.upload-modal.subtitle": "Upload a licence key for Mattermost Enterprise Edition to upgrade this server. ", "admin.license.upload-modal.successfulUpgrade": "Upgrade successful!", - "admin.license.upload-modal.successfulUpgradeText": "You have upgraded to the {skuName} plan for {licensedUsersNum, number} users. This is effective from {startsAt} until {expiresAt}. ", + "admin.license.upload-modal.successfulUpgradeText": "You have upgraded to the {skuName} plan for {licensedUsersNum, number} seats. This is effective from {startsAt} until {expiresAt}. ", "admin.license.upload-modal.title": "Upload a Licence Key", "admin.license.uploadFile": "Upload File", "admin.license.warn.renew": "Renew", @@ -4678,8 +4678,8 @@ "self_hosted_signup.cta": "Upgrade", "self_hosted_signup.disclaimer": "I have read and agree to the Enterprise Edition Subscription Terms", "self_hosted_signup.error_invalid_number": "Enter a valid number of seats", - "self_hosted_signup.error_max_seats": " licence purchase only supports purchases up to {num} users", - "self_hosted_signup.error_min_seats": "Your workspace currently has {num} users", + "self_hosted_signup.error_max_seats": " licence purchase only supports purchases up to {num} seats", + "self_hosted_signup.error_min_users": "Your workspace currently has {num} active users", "self_hosted_signup.failed_export.subtitle": "You will receive an email within 3 days to confirm the approval of your licence. In the meantime, please feel free to continue using the free version of our product.", "self_hosted_signup.failed_export.title": "Your transaction is being reviewed", "self_hosted_signup.license_applied": "Your {planName} licence has now been applied. {planName} features are now available and ready to use.", diff --git a/webapp/channels/src/i18n/es.json b/webapp/channels/src/i18n/es.json index 29c0bb0a86..225319f919 100644 --- a/webapp/channels/src/i18n/es.json +++ b/webapp/channels/src/i18n/es.json @@ -384,8 +384,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Impuestos", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Última factura", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Total", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} usuarios", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} usuarios", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "¿Qué son los cargos parciales?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Los usuarios que no se hayan habilitado durante todo el mes se les cobrará una tarifa mensual prorrateada.", "admin.billing.subscriptions.billing_summary.noBillingHistory.description": "En el futuro, aquí es donde se mostrará su resumen de factura más reciente.", @@ -1302,7 +1300,6 @@ "admin.license.upload-modal.file": "Archivo", "admin.license.upload-modal.subtitle": "Cargar una clave de licencia para Mattermost Enterprise Edition para actualizar este servidor. ", "admin.license.upload-modal.successfulUpgrade": "¡Actualización satisfactoria!", - "admin.license.upload-modal.successfulUpgradeText": "Has actualizado al plan {skuName} para los usuarios {licensedUsersNum, number}. Esto es efectivo a partir de {startsAt} y hasta {expiresAt}. ", "admin.license.upload-modal.title": "Cargar Clave de Licencia", "admin.license.uploadFile": "Cargar Archivo", "admin.license.warn.renew": "Renovar", diff --git a/webapp/channels/src/i18n/fa.json b/webapp/channels/src/i18n/fa.json index 784302be1a..1e2233cfa5 100644 --- a/webapp/channels/src/i18n/fa.json +++ b/webapp/channels/src/i18n/fa.json @@ -362,8 +362,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "مالیات", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "آخرین صورت‌حساب", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "جمع", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " × {users} کاربر", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} کاربر", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "نمایش فاکتور", "admin.billing.subscriptions.billing_summary.noBillingHistory.description": "در آینده، این جایی است که آخرین خلاصه صورتحساب شما نشان داده خواهد شد.", "admin.billing.subscriptions.billing_summary.noBillingHistory.link": "ببینید صورتحساب چگونه کار می کند", diff --git a/webapp/channels/src/i18n/fr.json b/webapp/channels/src/i18n/fr.json index 51356da7f1..7f3d3343e0 100644 --- a/webapp/channels/src/i18n/fr.json +++ b/webapp/channels/src/i18n/fr.json @@ -388,8 +388,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Taxes", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Dernière facture", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Total", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} utilisateurs", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} utilisateurs", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "Voir la facture", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "Qu'est-ce qu'un paiement partiel ?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Les utilisateurs qui n'ont pas été activés durant toute la durée du mois sont facturés proportionnellement au taux mensuel.", @@ -1282,7 +1280,6 @@ "admin.license.upload-modal.file": "Fichier", "admin.license.upload-modal.subtitle": "Téléchargez une clé de licence pour Mattermost Enterprise Edition pour mettre à niveau ce serveur. ", "admin.license.upload-modal.successfulUpgrade": "Mise à niveau réussie !", - "admin.license.upload-modal.successfulUpgradeText": "Vous avez mis à niveau vers le plan {skuName} pour {licensedUsersNum, number} utilisateurs. Ceci est valable du {startsAt} jusqu'au {expiresAt}. ", "admin.license.upload-modal.title": "Télécharger une clé de licence", "admin.license.uploadFile": "Télécharger un fichier", "admin.license.warn.renew": "Renouveller", diff --git a/webapp/channels/src/i18n/hu.json b/webapp/channels/src/i18n/hu.json index be4db12af4..7e12d2e722 100644 --- a/webapp/channels/src/i18n/hu.json +++ b/webapp/channels/src/i18n/hu.json @@ -372,8 +372,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Adók", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Utolsó számla", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Végösszeg", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} felhasználó", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} felhasználó", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "Mik azok a részleges díjak?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Azoknak a felhasználóknak, akiket nem a hónap teljes időtartama alatt engedélyeztek, arányos havi díjat számítunk fel.", "admin.billing.subscriptions.billing_summary.noBillingHistory.description": "A jövőben itt fog megjelenni a legutóbbi számlázási összefoglaló.", @@ -1285,7 +1283,6 @@ "admin.license.upload-modal.file": "Fájl", "admin.license.upload-modal.subtitle": "Töltse fel a Mattermost Enterprise Edition licenckulcsát a kiszolgáló frissítéséhez. ", "admin.license.upload-modal.successfulUpgrade": "Sikeres frissítés!", - "admin.license.upload-modal.successfulUpgradeText": "Ön a {licensedUsersNum, number} felhasználóra szóló {skuName} csomagra frissített. Az érvényességi idő {startsAt}-től {expiresAt}-ig tart. ", "admin.license.upload-modal.title": "Licensz fájl feltöltése", "admin.license.uploadFile": "Fájl feltöltése", "admin.license.warn.renew": "Megújítás", diff --git a/webapp/channels/src/i18n/ja.json b/webapp/channels/src/i18n/ja.json index 30838c9df8..bd1a74c190 100644 --- a/webapp/channels/src/i18n/ja.json +++ b/webapp/channels/src/i18n/ja.json @@ -412,8 +412,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "税", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "最新の請求書", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "総計", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} ユーザー", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} ユーザー", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "請求書を見る", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "一部課金とは?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "月の全期間において有効でなかったユーザーは、日割り計算で課金されます。", @@ -1355,7 +1353,6 @@ "admin.license.upload-modal.file": "ファイル", "admin.license.upload-modal.subtitle": "このサーバーをアップグレードするために、Mattermost Enterprise Editionのライセンスキーをアップロードしてください。 ", "admin.license.upload-modal.successfulUpgrade": "アップグレードが成功しました!", - "admin.license.upload-modal.successfulUpgradeText": "{licensedUsersNum, number} ユーザー向けの {skuName} プランにアップグレードされました。このプランは {startsAt} から {expiresAt} まで有効です。 ", "admin.license.upload-modal.title": "ライセンスキーのアップロード", "admin.license.uploadFile": "ファイルをアップロードする", "admin.license.warn.renew": "更新", @@ -4708,8 +4705,6 @@ "self_hosted_signup.cta": "アップグレード", "self_hosted_signup.disclaimer": "Enterprise Edition Subscription Termsを確認し、同意しました", "self_hosted_signup.error_invalid_number": "有効なシート数を入力してください", - "self_hosted_signup.error_max_seats": " ライセンス購入は、{num} ユーザーまでの購入のみに対応しています", - "self_hosted_signup.error_min_seats": "ワークスペースの現在のユーザー数は {num} ユーザーです", "self_hosted_signup.failed_export.subtitle": "あなたのライセンスが承認され次第、弊社側で確認を行い、3日以内に返信いたします。それまでの間は、Free版の製品を引き続きご利用ください。", "self_hosted_signup.failed_export.title": "取引きは審査中です", "self_hosted_signup.license_applied": "{planName} ライセンスが適用されました。{planName} の機能が利用可能になり、今すぐ使用することができます。", diff --git a/webapp/channels/src/i18n/ko.json b/webapp/channels/src/i18n/ko.json index b2ad76db44..a084d1bec5 100644 --- a/webapp/channels/src/i18n/ko.json +++ b/webapp/channels/src/i18n/ko.json @@ -380,8 +380,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "세금", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "마지막 인보이스", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "합계", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} 사용자", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} 사용자", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "청구서 보기", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "부분 청구 란 무엇입니까?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "해당 월의 전체 기간 동안 활성화되지 않은 사용자에게는 매월 비율에 따라 요금이 청구됩니다.", diff --git a/webapp/channels/src/i18n/nl.json b/webapp/channels/src/i18n/nl.json index f3a8aed7c4..8749449bac 100644 --- a/webapp/channels/src/i18n/nl.json +++ b/webapp/channels/src/i18n/nl.json @@ -412,8 +412,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Belasting", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Laatste factuur", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Totaal", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} gebruikers", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} gebruikers", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "Factuur bekijken", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "Wat zijn gedeeltelijke kosten?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Gebruikers die niet voor de volledige duur van de maand zijn ingeschakeld, worden maandelijks een evenredig bedrag in rekening gebracht.", @@ -1355,7 +1353,6 @@ "admin.license.upload-modal.file": "Bestand", "admin.license.upload-modal.subtitle": "Upload een licentiesleutel voor Mattermost Enterprise Edition om deze server te upgraden. ", "admin.license.upload-modal.successfulUpgrade": "Upgrade geslaagd!", - "admin.license.upload-modal.successfulUpgradeText": "Je hebt een upgrade naar het {skuName} plan voor {licensedUsersNum, number} gebruikers. Dit is van kracht vanaf {startsAt} tot {expiresAt}. ", "admin.license.upload-modal.title": "Licentiesleutel uploaden", "admin.license.uploadFile": "Bestand uploaden", "admin.license.warn.renew": "Vernieuwen", @@ -4693,8 +4690,6 @@ "self_hosted_signup.cta": "Upgraden", "self_hosted_signup.disclaimer": "Ik heb de abonnementsvoorwaarden voorEnterprise Edition gelezen en ga ermee akkoord", "self_hosted_signup.error_invalid_number": "Voer een geldig aantal zetels in", - "self_hosted_signup.error_max_seats": " licentieaankoop ondersteunt alleen aankopen tot {num} gebruikers", - "self_hosted_signup.error_min_seats": "Jouw werkruimte heeft momenteel {num} gebruikers", "self_hosted_signup.failed_export.subtitle": "Wij controleren de zaken aan onze kant en nemen binnen 3 dagen contact met jou op zodra jouuw licentie is goedgekeurd. In de tussentijd kan je gerust de gratis versie van ons product blijven gebruiken.", "self_hosted_signup.failed_export.title": "Jouw transactie wordt bekeken", "self_hosted_signup.license_applied": "Jouw {planName} licentie is nu toegepast. {planName} functies zijn nu beschikbaar en klaar voor gebruik.", diff --git a/webapp/channels/src/i18n/pl.json b/webapp/channels/src/i18n/pl.json index c4784f3d61..b7d9d75387 100644 --- a/webapp/channels/src/i18n/pl.json +++ b/webapp/channels/src/i18n/pl.json @@ -412,8 +412,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Podatki", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Ostatnia faktura", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Ogółem", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} użytkowników", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} użytkowników", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "Zobacz fakturę", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "Co to są opłaty częściowe?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Użytkownicy, którzy nie byli aktywni przez cały okres miesiąca, są obciążani proporcjonalną stawką miesięczną.", @@ -1355,7 +1353,6 @@ "admin.license.upload-modal.file": "Plik", "admin.license.upload-modal.subtitle": "Prześlij klucz licencyjny dla Mattermost Enterprise Edition, aby uaktualnić ten serwer. ", "admin.license.upload-modal.successfulUpgrade": "Udana aktualizacja!", - "admin.license.upload-modal.successfulUpgradeText": "Dokonałeś aktualizacji do planu {skuName} dla użytkowników {licensedUsersNum, number}. Obowiązuje to od {startsAt} do {expiresAt}. ", "admin.license.upload-modal.title": "Prześlij klucz licencyjny", "admin.license.uploadFile": "Prześlij plik", "admin.license.warn.renew": "Ponów", @@ -4708,8 +4705,6 @@ "self_hosted_signup.cta": "Aktualizuj", "self_hosted_signup.disclaimer": "Zapoznałem się i akceptuję warunki subskrypcji Enterprise Edition.", "self_hosted_signup.error_invalid_number": "Wprowadź prawidłową liczbę miejsc", - "self_hosted_signup.error_max_seats": " zakup licencji obsługuje tylko zakupy do {num} użytkowników", - "self_hosted_signup.error_min_seats": "W Twojej przestrzeni roboczej znajduje się obecnie {num} użytkowników", "self_hosted_signup.failed_export.subtitle": "Sprawdzimy wszystko po naszej stronie i skontaktujemy się z Tobą w ciągu 3 dni po zatwierdzeniu licencji. W międzyczasie prosimy o dalsze korzystanie z darmowej wersji naszego produktu.", "self_hosted_signup.failed_export.title": "Twoja transakcja jest sprawdzana", "self_hosted_signup.license_applied": "Twoja licencja {planName} została zastosowana. Funkcje {planName} są teraz dostępne i gotowe do użycia.", diff --git a/webapp/channels/src/i18n/pt-BR.json b/webapp/channels/src/i18n/pt-BR.json index bf21ed7ea1..5e15accc5d 100644 --- a/webapp/channels/src/i18n/pt-BR.json +++ b/webapp/channels/src/i18n/pt-BR.json @@ -306,8 +306,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Taxas", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Última Fatura", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Total", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} usuários", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} usuários", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "O que são cobranças parciais?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Os usuários que não foram ativados durante todo o mês são cobrados a uma taxa mensal rateada.", "admin.billing.subscriptions.billing_summary.noBillingHistory.description": "No futuro, é aqui que o resumo de sua fatura mais recente será exibido.", diff --git a/webapp/channels/src/i18n/ro.json b/webapp/channels/src/i18n/ro.json index 19769ccd8d..62a0b57261 100644 --- a/webapp/channels/src/i18n/ro.json +++ b/webapp/channels/src/i18n/ro.json @@ -307,8 +307,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Taxe", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Ultima factură", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Total", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} utilizatori", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} utilizatori", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "Ce sunt taxele parțiale?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Utilizatorii care nu au fost activați pe toată durata lunii sunt taxați la o rată lunară proporțională.", "admin.billing.subscriptions.billing_summary.noBillingHistory.description": "În viitor, aici va apărea cel mai recent rezumat al facturii.", diff --git a/webapp/channels/src/i18n/ru.json b/webapp/channels/src/i18n/ru.json index ee870bc6a2..26a1ff7a33 100644 --- a/webapp/channels/src/i18n/ru.json +++ b/webapp/channels/src/i18n/ru.json @@ -412,8 +412,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Налоги", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Последний счёт", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Всего", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} пользователей", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} пользователей", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "Просмотреть счет-фактуру", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "Что такое частичные оплаты?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Пользователи, которые не были подключены в течение всего месяца, оплачиваются пропорционально по месячному тарифу.", @@ -1355,7 +1353,6 @@ "admin.license.upload-modal.file": "Файл", "admin.license.upload-modal.subtitle": "Загрузите лицензионный ключ для Mattermost Enterprise Edition, чтобы обновить этот сервер. ", "admin.license.upload-modal.successfulUpgrade": "Обновление прошло успешно!", - "admin.license.upload-modal.successfulUpgradeText": "Вы перешли на план {skuName} для {licensedUsersNum, number} пользователей. План действует с {startsAt} до {expiresAt}. ", "admin.license.upload-modal.title": "Загрузить лицензионный ключ", "admin.license.uploadFile": "Загрузить файл", "admin.license.warn.renew": "Продлить", @@ -4695,8 +4692,6 @@ "self_hosted_signup.cta": "Обновить", "self_hosted_signup.disclaimer": "Я прочитал и согласен с условиями подписки на Enterprise Edition.", "self_hosted_signup.error_invalid_number": "Введите действительное количество рабочих мест", - "self_hosted_signup.error_max_seats": " приобретение лицензий поддерживает покупку только до {num} пользователей", - "self_hosted_signup.error_min_seats": "В вашем рабочем пространстве в настоящее время {num} пользователей", "self_hosted_signup.failed_export.subtitle": "Мы проверим ситуацию на нашей стороне и свяжемся с вами в течение 3 дней, когда ваша лицензия будет одобрена. Тем временем, пожалуйста, продолжайте пользоваться бесплатной версией нашего продукта.", "self_hosted_signup.failed_export.title": "Ваша транзакция находится на рассмотрении", "self_hosted_signup.license_applied": "Ваша лицензия {planName} была применена. Функции {planName} теперь доступны и готовы к использованию.", diff --git a/webapp/channels/src/i18n/sv.json b/webapp/channels/src/i18n/sv.json index 6f2c7bc76c..2385037c1f 100644 --- a/webapp/channels/src/i18n/sv.json +++ b/webapp/channels/src/i18n/sv.json @@ -412,8 +412,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Skatt", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Senaste fakturan", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Summa", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} användare", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} användare", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "Visa faktura", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "Vad är delbetalningar?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Användare som inte varit aktiverade under hela månadsperioden debiteras med delbetalning.", @@ -1355,7 +1353,6 @@ "admin.license.upload-modal.file": "Fil", "admin.license.upload-modal.subtitle": "Ladda upp en licensnyckel för Mattermost Enterprise Edition för att uppgradera den här servern. ", "admin.license.upload-modal.successfulUpgrade": "Uppgraderingen lyckades!", - "admin.license.upload-modal.successfulUpgradeText": "Du har uppgraderat till planen {skuName} för {licensedUsersNum, number} användare. Detta gäller från {startsAt} till {expiresAt}. ", "admin.license.upload-modal.title": "Ladda upp en licensnyckel", "admin.license.uploadFile": "Ladda upp fil", "admin.license.warn.renew": "Förnya", @@ -4695,8 +4692,6 @@ "self_hosted_signup.cta": "Uppdatera", "self_hosted_signup.disclaimer": "Jag har läst och godkänner prenumerationsvillkoren för Enterprise Edition.", "self_hosted_signup.error_invalid_number": "Ange ett giltigt antal platser", - "self_hosted_signup.error_max_seats": " licensköp kan endast göras upp till {num} användare", - "self_hosted_signup.error_min_seats": "Din arbetsyta har just nu {num} användare", "self_hosted_signup.failed_export.subtitle": "Vi kommer kontrollera några saker på vår sida och när din licens är godkänd återkommer vi till dig inom tre dagar. Under tiden kan du gärna fortsätta att använda gratisversionen av vår produkt.", "self_hosted_signup.failed_export.title": "Din transaktion granskas", "self_hosted_signup.license_applied": "Din {planName} -licens har nu tillämpats. {planName} -funktionerna är nu tillgängliga och redo att användas.", diff --git a/webapp/channels/src/i18n/tr.json b/webapp/channels/src/i18n/tr.json index d61c34f273..3551655a41 100644 --- a/webapp/channels/src/i18n/tr.json +++ b/webapp/channels/src/i18n/tr.json @@ -389,8 +389,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Vergiler", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Son fatura", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Toplam", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} kullanıcı", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} kullanıcı", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "Faturayı görüntüle", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "Kısmi ödemeler nedir?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Ayın tamamı boyunca etkin olmayan kullanıcılardan aylık kullanım ile orantılı bir ödeme alınır.", @@ -1332,7 +1330,6 @@ "admin.license.upload-modal.file": "Dosya", "admin.license.upload-modal.subtitle": "Bu sunucuyu üst tarifeye geçirmek için bir Mattermost Enterprise paketi lisans anahtarı yükleyin. ", "admin.license.upload-modal.successfulUpgrade": "Üst tarifeye geçildi!", - "admin.license.upload-modal.successfulUpgradeText": "{licensedUsersNum, number} kullanıcı için {skuName} tarifesine geçtiniz. {startsAt} ile {expiresAt} tarihleri arasında geçerli olacak. ", "admin.license.upload-modal.title": "Bir lisans anahtarı yükleyin", "admin.license.uploadFile": "Dosya yükle", "admin.license.warn.renew": "Yenile", @@ -4596,8 +4593,6 @@ "self_hosted_signup.cta": "Yükselt", "self_hosted_signup.disclaimer": "Enterprise Edition abonelik koşullarını okudum ve kabul ediyorum", "self_hosted_signup.error_invalid_number": "Geçerli bir koltuk lisansı sayısı yazın", - "self_hosted_signup.error_max_seats": " yalnızca {num} kullanıcıya kadar lisans satın alımı desteklenir", - "self_hosted_signup.error_min_seats": "Çalışma alanınızda şu anda {num} kullanıcı var", "self_hosted_signup.failed_export.subtitle": "Kontrollerimizi yapacağız ve lisansınızı onaylandıktan sonra 3 gün içinde size geri döneceğiz. Bu arada, lütfen ürünümüzün ücretsiz sürümünü kullanmayı sürdürmekten çekinmeyin.", "self_hosted_signup.failed_export.title": "İşleminiz inceleniyor", "self_hosted_signup.license_applied": "{planName} lisansınız etkinleştirildi. {planName} özelliklerini kullanabilirsiniz.", diff --git a/webapp/channels/src/i18n/zh-CN.json b/webapp/channels/src/i18n/zh-CN.json index 726b018637..0cd759a140 100644 --- a/webapp/channels/src/i18n/zh-CN.json +++ b/webapp/channels/src/i18n/zh-CN.json @@ -399,8 +399,6 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "税", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "最后发票", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "总计", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} 用户", - "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} 用户", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "什么是部分费用?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "在一个月的整个时间内未启用的用户将按比例按月计费。", "admin.billing.subscriptions.billing_summary.noBillingHistory.description": "将来,这是您最近的帐单摘要将显示的位置。", From 0807d5e3f0c4c96a566a09131406d4db26fed6da Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Thu, 30 Mar 2023 16:51:05 -0400 Subject: [PATCH 04/58] lint, i18n. --- .../src/components/admin_console/billing/invoice_user_count.tsx | 1 + webapp/channels/src/i18n/en.json | 1 + 2 files changed, 2 insertions(+) diff --git a/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx b/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx index 20d17c0bb1..e7228addf5 100644 --- a/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx +++ b/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx @@ -21,6 +21,7 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele id='admin.billing.history.onPremSeats' defaultMessage='{num} seats' values={{ + // should always be a whole number, but truncate just in case num: Math.floor(onPremUsers), }} diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index 35c493f09b..a8331a1606 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -265,6 +265,7 @@ "admin.billing.history.allPaymentsShowHere": "All of your invoices will be shown here", "admin.billing.history.date": "Date", "admin.billing.history.description": "Description", + "admin.billing.history.fractionalAndRatedSeats": "{fractionalSeats} metered seats, {fullSeats} seats at full rate, {partialSeats} seats with partial charges", "admin.billing.history.fractionalSeats": "{fractionalUsers} seats", "admin.billing.history.noBillingHistory": "In the future, this is where your billing history will show.", "admin.billing.history.onPremSeats": "{num} seats", From d301c91ebd12b51da6ec8a3a0cb5e83da7a15d8d Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Thu, 30 Mar 2023 17:02:00 -0400 Subject: [PATCH 05/58] lint. --- .../src/components/admin_console/billing/invoice_user_count.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx b/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx index e7228addf5..c93be8af8e 100644 --- a/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx +++ b/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx @@ -21,7 +21,7 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele id='admin.billing.history.onPremSeats' defaultMessage='{num} seats' values={{ - + // should always be a whole number, but truncate just in case num: Math.floor(onPremUsers), }} From 5ddec36ea54ef0495083d942eb95df97ddeaaea7 Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Thu, 30 Mar 2023 17:04:25 -0400 Subject: [PATCH 06/58] i18n fix. --- webapp/channels/src/i18n/en.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index a8331a1606..50d3e787dd 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -273,12 +273,12 @@ "admin.billing.history.paid": "Paid", "admin.billing.history.paymentFailed": "Payment failed", "admin.billing.history.pending": "Pending", + "admin.billing.history.seatsAndRates": "{fullUsers} seats at full rate, {partialUsers} seats with partial charges", "admin.billing.history.seeHowBillingWorks": "See how billing works", "admin.billing.history.status": "Status", "admin.billing.history.title": "Billing History", "admin.billing.history.total": "Total", "admin.billing.history.transactions": "Transactions", - "admin.billing.history.seatsAndRates": "{fullUsers} seats at full rate, {partialUsers} seats with partial charges", "admin.billing.payment_info_display.allCardsAccepted": "All major credit cards are accepted.", "admin.billing.payment_info_display.noPaymentInfo": "There are currently no credit cards on file.", "admin.billing.payment_info_display.savedPaymentDetails": "Your saved payment details", @@ -412,12 +412,12 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.paid": "Paid", "admin.billing.subscriptions.billing_summary.lastInvoice.partialCharges": "Partial charges", "admin.billing.subscriptions.billing_summary.lastInvoice.pending": "Pending", + "admin.billing.subscriptions.billing_summary.lastInvoice.seatCount": " x {seats} seats", + "admin.billing.subscriptions.billing_summary.lastInvoice.seatCountPartial": "{seats} seats", "admin.billing.subscriptions.billing_summary.lastInvoice.seeBillingHistory": "See Billing History", "admin.billing.subscriptions.billing_summary.lastInvoice.taxes": "Taxes", "admin.billing.subscriptions.billing_summary.lastInvoice.title": "Last Invoice", "admin.billing.subscriptions.billing_summary.lastInvoice.total": "Total", - "admin.billing.subscriptions.billing_summary.lastInvoice.seatCount": " x {seats} seats", - "admin.billing.subscriptions.billing_summary.lastInvoice.seatCountPartial": "{seats} seats", "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "View Invoice", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "What are partial charges?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "Users who have not been enabled for the full duration of the month are charged at a prorated monthly rate.", From 87abaca763a12a09fc040892c9a777fa68fc0134 Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Fri, 31 Mar 2023 09:09:02 -0400 Subject: [PATCH 07/58] fix tests. --- .../billing/invoice_user_count.test.tsx | 16 ++++++++-------- .../enterprise_edition_left_panel.test.tsx | 2 +- .../self_hosted_purchase_modal/index.test.tsx | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx b/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx index b65bc918e6..cdaf54db11 100644 --- a/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx @@ -51,28 +51,28 @@ describe('InvoiceUserCount', () => { [1, InvoiceLineItemType.Full], [1, InvoiceLineItemType.Partial], ), - expected: '1 metered users, 1 users at full rate, 1 users with partial charges', + expected: '1 metered seats, 1 seats at full rate, 1 seats with partial charges', }, { name: 'Supports cloud invoices with only metered line items', invoice: makeInvoice( [12.34, InvoiceLineItemType.Metered], ), - expected: '12.34 users', + expected: '12.34 seats', }, { name: 'Shows minimum decimal necessary', invoice: makeInvoice( [12.499, InvoiceLineItemType.Metered], ), - expected: '12.5 users', + expected: '12.5 seats', }, { name: 'hides insignificant decimals', invoice: makeInvoice( [12.002, InvoiceLineItemType.Metered], ), - expected: '12 users', + expected: '12 seats', }, { name: 'Supports cloud invoices with only non-metered line items', @@ -80,7 +80,7 @@ describe('InvoiceUserCount', () => { [1, InvoiceLineItemType.Full], [249, InvoiceLineItemType.Partial], ), - expected: '1 users at full rate, 249 users with partial charges', + expected: '1 seat at full rate, 249 users with partial charges', }, { name: 'Shows default of 0 full users, 0 partial users when there are no users', @@ -89,19 +89,19 @@ describe('InvoiceUserCount', () => { [0, InvoiceLineItemType.Full], [0, InvoiceLineItemType.Partial], ), - expected: '0 users at full rate, 0 users with partial charges', + expected: '0 seats at full rate, 0 seats with partial charges', }, { name: 'Shows default of 0 full users, 0 partial users when there are no line items in invoice', invoice: makeInvoice(), - expected: '0 users at full rate, 0 users with partial charges', + expected: '0 seats at full rate, 0 seats with partial charges', }, { name: 'Shows 3 full userswhen there are on prem users', invoice: makeInvoice( [3, InvoiceLineItemType.OnPremise], ), - expected: '3 users', + expected: '3 seats', }, ]; diff --git a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.test.tsx b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.test.tsx index ef6a3d387f..603aa6807b 100644 --- a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.test.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.test.tsx @@ -82,7 +82,7 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris return n.children().length === 2 && n.childAt(0).type() === 'span' && !n.childAt(0).text().includes('ACTIVE') && - n.childAt(0).text().includes('USERS'); + n.childAt(0).text().includes('LICENSED SEATS'); }); expect(item.text()).toContain('1,000,000'); diff --git a/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx b/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx index 81437b3d7a..0101b979c4 100644 --- a/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx +++ b/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx @@ -275,7 +275,7 @@ describe('SelfHostedPurchaseModal', () => { const tooFewSeats = existingUsers - 1; fireEvent.change(screen.getByTestId('selfHostedPurchaseSeatsInput'), valueEvent(tooFewSeats.toString())); expect(screen.getByText('Upgrade')).toBeDisabled(); - screen.getByText('Your workspace currently has 10 users', {exact: false}); + screen.getByText('Your workspace currently has 10 seats', {exact: false}); }); it('happy path submit shows success screen', async () => { From 2eda7f24c985b979951742c56dbc7b054ca8108d Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Fri, 31 Mar 2023 10:14:01 -0400 Subject: [PATCH 08/58] revert changes to one translation. --- webapp/channels/src/components/seats_calculator/index.tsx | 4 ++-- .../src/components/self_hosted_purchase_modal/index.test.tsx | 2 +- webapp/channels/src/i18n/de.json | 1 + webapp/channels/src/i18n/en.json | 2 +- webapp/channels/src/i18n/en_AU.json | 2 +- webapp/channels/src/i18n/ja.json | 1 + webapp/channels/src/i18n/nl.json | 1 + webapp/channels/src/i18n/pl.json | 1 + webapp/channels/src/i18n/ru.json | 1 + webapp/channels/src/i18n/sv.json | 1 + webapp/channels/src/i18n/tr.json | 1 + 11 files changed, 12 insertions(+), 5 deletions(-) diff --git a/webapp/channels/src/components/seats_calculator/index.tsx b/webapp/channels/src/components/seats_calculator/index.tsx index e5bd5edcaf..fe2b9259a2 100644 --- a/webapp/channels/src/components/seats_calculator/index.tsx +++ b/webapp/channels/src/components/seats_calculator/index.tsx @@ -61,8 +61,8 @@ function validateSeats(seats: string, annualPricePerSeat: number, minSeats: numb const maxSeats = calculateMaxUsers(annualPricePerSeat); const tooFewUsersErrorMessage = ( , }} diff --git a/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx b/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx index 0101b979c4..f9c57ac38d 100644 --- a/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx +++ b/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx @@ -275,7 +275,7 @@ describe('SelfHostedPurchaseModal', () => { const tooFewSeats = existingUsers - 1; fireEvent.change(screen.getByTestId('selfHostedPurchaseSeatsInput'), valueEvent(tooFewSeats.toString())); expect(screen.getByText('Upgrade')).toBeDisabled(); - screen.getByText('Your workspace currently has 10 seats', {exact: false}); + screen.getByText('Your workspace currently has 10 active users', {exact: false}); }); it('happy path submit shows success screen', async () => { diff --git a/webapp/channels/src/i18n/de.json b/webapp/channels/src/i18n/de.json index 5a34d538a1..51a3b6bae5 100644 --- a/webapp/channels/src/i18n/de.json +++ b/webapp/channels/src/i18n/de.json @@ -4717,6 +4717,7 @@ "self_hosted_signup.purchase_in_progress.by_self_restart": "Wenn du der Meinung bist, dass dies ein Fehler ist, starte den Kauf erneut.", "self_hosted_signup.purchase_in_progress.reset": "Kaufvorgang erneut starten", "self_hosted_signup.purchase_in_progress.title": "Kauf in Bearbeitung", + "self_hosted_signup.error_min_seats": "Dein Arbeitsbereich hat derzeit {num} Benutzer", "self_hosted_signup.retry": "Erneut versuchen", "self_hosted_signup.screening_description": "Wir werden die Dinge von unserer Seite aus überprüfen und uns innerhalb von 3 Tagen bei dir melden, sobald deine Lizenz genehmigt ist. In der Zwischenzeit kannst du gerne die kostenlose Version unseres Produkts weiter nutzen.", "self_hosted_signup.screening_title": "Deine Transaktion wird überprüft", diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index 50d3e787dd..ef5e0dfdde 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -4708,7 +4708,7 @@ "self_hosted_signup.disclaimer": "I have read and agree to the Enterprise Edition Subscription Terms", "self_hosted_signup.error_invalid_number": "Enter a valid number of seats", "self_hosted_signup.error_max_seats": " license purchase only supports purchases up to {num} seats", - "self_hosted_signup.error_min_users": "Your workspace currently has {num} active users", + "self_hosted_signup.error_min_seats": "Your workspace currently has {num} users", "self_hosted_signup.failed_export.subtitle": "We will check things on our side and get back to you within 3 days once your license is approved. In the meantime, please feel free to continue using the free version of our product.", "self_hosted_signup.failed_export.title": "Your transaction is being reviewed", "self_hosted_signup.license_applied": "Your {planName} license has now been applied. {planName} features are now available and ready to use.", diff --git a/webapp/channels/src/i18n/en_AU.json b/webapp/channels/src/i18n/en_AU.json index 16b3a1b373..62c7224ba2 100644 --- a/webapp/channels/src/i18n/en_AU.json +++ b/webapp/channels/src/i18n/en_AU.json @@ -4679,7 +4679,7 @@ "self_hosted_signup.disclaimer": "I have read and agree to the Enterprise Edition Subscription Terms", "self_hosted_signup.error_invalid_number": "Enter a valid number of seats", "self_hosted_signup.error_max_seats": " licence purchase only supports purchases up to {num} seats", - "self_hosted_signup.error_min_users": "Your workspace currently has {num} active users", + "self_hosted_signup.error_min_seats": "Your workspace currently has {num} users", "self_hosted_signup.failed_export.subtitle": "You will receive an email within 3 days to confirm the approval of your licence. In the meantime, please feel free to continue using the free version of our product.", "self_hosted_signup.failed_export.title": "Your transaction is being reviewed", "self_hosted_signup.license_applied": "Your {planName} licence has now been applied. {planName} features are now available and ready to use.", diff --git a/webapp/channels/src/i18n/ja.json b/webapp/channels/src/i18n/ja.json index bd1a74c190..8036413f25 100644 --- a/webapp/channels/src/i18n/ja.json +++ b/webapp/channels/src/i18n/ja.json @@ -4717,6 +4717,7 @@ "self_hosted_signup.purchase_in_progress.by_self_restart": "間違いがある場合、購入をやり直してください。", "self_hosted_signup.purchase_in_progress.reset": "購入をやり直す", "self_hosted_signup.purchase_in_progress.title": "進行中の購入", + "self_hosted_signup.error_min_seats": "ワークスペースの現在のユーザー数は {num} ユーザーです", "self_hosted_signup.retry": "際実行", "self_hosted_signup.screening_description": "あなたのライセンスが承認され次第、弊社側で確認を行い、3日以内に返信いたします。それまでの間は、Free版の製品を引き続きご利用ください。", "self_hosted_signup.screening_title": "取引きは審査中です", diff --git a/webapp/channels/src/i18n/nl.json b/webapp/channels/src/i18n/nl.json index 8749449bac..124926d53a 100644 --- a/webapp/channels/src/i18n/nl.json +++ b/webapp/channels/src/i18n/nl.json @@ -4702,6 +4702,7 @@ "self_hosted_signup.purchase_in_progress.by_self_restart": "Als je denkt dat dit een vergissing is, start jouw aankoop opnieuw.", "self_hosted_signup.purchase_in_progress.reset": "Aankoop opnieuw starten", "self_hosted_signup.purchase_in_progress.title": "Aankoop in uitvoering", + "self_hosted_signup.error_min_seats": "Jouw werkruimte heeft momenteel {num} gebruikers", "self_hosted_signup.retry": "Probeer opnieuw", "self_hosted_signup.screening_description": "Wij controleren de zaken aan onze kant en nemen binnen 3 dagen contact met jou op zodra jouuw licentie is goedgekeurd. In de tussentijd kan je gerust de gratis versie van ons product blijven gebruiken.", "self_hosted_signup.screening_title": "Jouw transactie wordt bekeken", diff --git a/webapp/channels/src/i18n/pl.json b/webapp/channels/src/i18n/pl.json index b7d9d75387..74d6a982f9 100644 --- a/webapp/channels/src/i18n/pl.json +++ b/webapp/channels/src/i18n/pl.json @@ -4717,6 +4717,7 @@ "self_hosted_signup.purchase_in_progress.by_self_restart": "Jeśli uważasz, że to błąd, zrestartuj swój zakup.", "self_hosted_signup.purchase_in_progress.reset": "Ponowne uruchomienie zakupu", "self_hosted_signup.purchase_in_progress.title": "Zakupy w toku", + "self_hosted_signup.error_min_seats": "W Twojej przestrzeni roboczej znajduje się obecnie {num} użytkowników", "self_hosted_signup.retry": "Spróbuj ponownie", "self_hosted_signup.screening_description": "Sprawdzimy wszystko po naszej stronie i skontaktujemy się z Tobą w ciągu 3 dni po zatwierdzeniu licencji. W międzyczasie prosimy o dalsze korzystanie z darmowej wersji naszego produktu.", "self_hosted_signup.screening_title": "Twoja transakcja jest sprawdzana", diff --git a/webapp/channels/src/i18n/ru.json b/webapp/channels/src/i18n/ru.json index 26a1ff7a33..57fb0e5d79 100644 --- a/webapp/channels/src/i18n/ru.json +++ b/webapp/channels/src/i18n/ru.json @@ -4704,6 +4704,7 @@ "self_hosted_signup.purchase_in_progress.by_self_restart": "Если вы считаете, что это ошибка, перезапустите покупку.", "self_hosted_signup.purchase_in_progress.reset": "Перезапуск покупки", "self_hosted_signup.purchase_in_progress.title": "Покупка в процессе", + "self_hosted_signup.error_min_seats": "В вашем рабочем пространстве в настоящее время {num} пользователей", "self_hosted_signup.retry": "Попробовать снова", "self_hosted_signup.screening_description": "Мы проверим ситуацию на нашей стороне и свяжемся с вами в течение 3 дней, когда ваша лицензия будет одобрена. Тем временем, пожалуйста, продолжайте пользоваться бесплатной версией нашего продукта.", "self_hosted_signup.screening_title": "Ваша транзакция находится на рассмотрении", diff --git a/webapp/channels/src/i18n/sv.json b/webapp/channels/src/i18n/sv.json index 2385037c1f..7678f8b430 100644 --- a/webapp/channels/src/i18n/sv.json +++ b/webapp/channels/src/i18n/sv.json @@ -4704,6 +4704,7 @@ "self_hosted_signup.purchase_in_progress.by_self_restart": "Om du tror att detta är ett misstag, starta om ditt köp från början igen.", "self_hosted_signup.purchase_in_progress.reset": "Börja om köpet", "self_hosted_signup.purchase_in_progress.title": "Inköp pågår", + "self_hosted_signup.error_min_seats": "Din arbetsyta har just nu {num} användare", "self_hosted_signup.retry": "Försök igen", "self_hosted_signup.screening_description": "Vi kommer att kontrollera saker och ting från vår sida och återkommer till dig inom tre dagar när din licens är godkänd. Under tiden kan du gärna fortsätta att använda gratisversionen av vår produkt.", "self_hosted_signup.screening_title": "Din transaktion håller på att granskas", diff --git a/webapp/channels/src/i18n/tr.json b/webapp/channels/src/i18n/tr.json index 3551655a41..1ba34e3b9b 100644 --- a/webapp/channels/src/i18n/tr.json +++ b/webapp/channels/src/i18n/tr.json @@ -4605,6 +4605,7 @@ "self_hosted_signup.purchase_in_progress.by_self_restart": "Bir hata olduğunu düşünüyorsanız, satın alma işleminizi yeniden başlatın.", "self_hosted_signup.purchase_in_progress.reset": "Satın almayı yeniden başlat", "self_hosted_signup.purchase_in_progress.title": "Satın alma işlemi sürüyor", + "self_hosted_signup.error_min_seats": "Çalışma alanınızda şu anda {num} kullanıcı var", "self_hosted_signup.retry": "Yeniden dene", "self_hosted_signup.screening_description": "Kontrollerimizi yapacağız ve lisansınızı onaylandıktan sonra 3 gün içinde size geri döneceğiz. Bu arada, lütfen ürünümüzün ücretsiz sürümünü kullanmayı sürdürmekten çekinmeyin.", "self_hosted_signup.screening_title": "İşleminiz inceleniyor", From a11e5357e33548e0cd389ae3b5b849556df4cbde Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Fri, 31 Mar 2023 10:14:35 -0400 Subject: [PATCH 09/58] fix tests. --- .../enterprise/cloud/billing/yearly_subscription_spec.js | 2 +- .../enterprise/self-hosted/self_hosted_purchase_spec.ts | 2 +- .../src/components/self_hosted_purchase_modal/index.test.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/cloud/billing/yearly_subscription_spec.js b/e2e-tests/cypress/tests/integration/channels/enterprise/cloud/billing/yearly_subscription_spec.js index 5351459903..0eacc1350c 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/cloud/billing/yearly_subscription_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/cloud/billing/yearly_subscription_spec.js @@ -147,7 +147,7 @@ describe('System Console - Subscriptions section', () => { // * Ensure that the yearly, monthly, and yearly saving prices match the new user seats value entered checkValues(lessThanUserCount); - cy.get('.RHS').get('.Input___customMessage').contains(`Your workspace currently has ${count} active users`); + cy.get('.RHS').get('.Input___customMessage').contains(`Your workspace currently has ${count} users`); // * Check that Upgrade button is not enabled cy.get('.RHS').find('button').should('be.disabled'); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/self-hosted/self_hosted_purchase_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/self-hosted/self_hosted_purchase_spec.ts index cbbe859a82..a21f5994b1 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/self-hosted/self_hosted_purchase_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/self-hosted/self_hosted_purchase_spec.ts @@ -340,7 +340,7 @@ describe('Self hosted Purchase', () => { getCurrentUsers().then((currentUsers) => { // * Verify form can not be submitted - cy.contains(`Your workspace currently has ${currentUsers} active users`).should('not.be.enabled'); + cy.contains(`Your workspace currently has ${currentUsers} users`).should('not.be.enabled'); cy.contains('Upgrade').should('not.be.enabled'); // # Fill form the same number of seats as current users diff --git a/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx b/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx index f9c57ac38d..81437b3d7a 100644 --- a/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx +++ b/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx @@ -275,7 +275,7 @@ describe('SelfHostedPurchaseModal', () => { const tooFewSeats = existingUsers - 1; fireEvent.change(screen.getByTestId('selfHostedPurchaseSeatsInput'), valueEvent(tooFewSeats.toString())); expect(screen.getByText('Upgrade')).toBeDisabled(); - screen.getByText('Your workspace currently has 10 active users', {exact: false}); + screen.getByText('Your workspace currently has 10 users', {exact: false}); }); it('happy path submit shows success screen', async () => { From bc788ce9e31375846dd117751a47bccb511ea78f Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Fri, 31 Mar 2023 13:21:39 -0400 Subject: [PATCH 10/58] fix tests. --- .../admin_console/billing/invoice_user_count.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx b/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx index cdaf54db11..e4f6e098f4 100644 --- a/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx @@ -80,7 +80,7 @@ describe('InvoiceUserCount', () => { [1, InvoiceLineItemType.Full], [249, InvoiceLineItemType.Partial], ), - expected: '1 seat at full rate, 249 users with partial charges', + expected: '1 seats at full rate, 249 seats with partial charges', }, { name: 'Shows default of 0 full users, 0 partial users when there are no users', From 72cd7ac4e05c0b6c84b229000477845fbdabe3b5 Mon Sep 17 00:00:00 2001 From: Julien Tant <785518+JulienTant@users.noreply.github.com> Date: Mon, 3 Apr 2023 09:20:44 -0700 Subject: [PATCH 11/58] [MM-51098] Hide "copy invite link" when selecting guest - migrated from webapp (#22745) --- .../guest_accounts/guest_invitation_ui_spec.ts | 11 +++++++++++ .../src/components/invitation_modal/invite_view.scss | 4 ++++ .../src/components/invitation_modal/invite_view.tsx | 5 +++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/guest_invitation_ui_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/guest_invitation_ui_spec.ts index aa12dae759..396869cd8e 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/guest_invitation_ui_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/guest_invitation_ui_spec.ts @@ -223,4 +223,15 @@ describe('Guest Account - Guest User Invitation Flow', () => { // * Verify invite more button is present cy.findByTestId('invite-more').should('be.visible'); }); + + it('hides the copy link button when inviting guests', () => { + // # Open team menu and click 'Invite People' + cy.uiOpenTeamMenu('Invite People'); + + // # Select Guest + cy.findByTestId('inviteGuestLink').should('be.visible').click(); + + // * The button "Copy invite link" should not exist + cy.findByTestId('InviteView__copyInviteLink').should('not.exist'); + }); }); diff --git a/webapp/channels/src/components/invitation_modal/invite_view.scss b/webapp/channels/src/components/invitation_modal/invite_view.scss index ec33fae3d5..b953080c26 100644 --- a/webapp/channels/src/components/invitation_modal/invite_view.scss +++ b/webapp/channels/src/components/invitation_modal/invite_view.scss @@ -51,6 +51,10 @@ button.InviteView__copyLink.tertiary-button:focus { display: none; } + &-guest { + justify-content: flex-end; + } + .btn { font-weight: 600; } diff --git a/webapp/channels/src/components/invitation_modal/invite_view.tsx b/webapp/channels/src/components/invitation_modal/invite_view.tsx index a67f53c9b5..9d6ec6292a 100644 --- a/webapp/channels/src/components/invitation_modal/invite_view.tsx +++ b/webapp/channels/src/components/invitation_modal/invite_view.tsx @@ -4,6 +4,7 @@ import React, {useEffect, useMemo} from 'react'; import {Modal} from 'react-bootstrap'; import {FormattedMessage, useIntl} from 'react-intl'; +import classNames from 'classnames'; import deepFreeze from 'mattermost-redux/utils/deep_freeze'; import {Channel} from '@mattermost/types/channels'; @@ -259,8 +260,8 @@ export default function InviteView(props: Props) { )} - - {copyButton} + + {props.inviteType === InviteType.MEMBER && copyButton}
@@ -126,11 +126,12 @@ exports[`components/GenericModal should match snapshot with both buttons 1`] = `
-`; - -exports[`components/marketplace/ AllListing should render with one plugin 1`] = ` - -`; - -exports[`components/marketplace/ AllListing should render with plugins 1`] = ` - -`; - -exports[`components/marketplace/ InstalledPlugins should render with multiple plugins 1`] = ` - -`; - -exports[`components/marketplace/ InstalledPlugins should render with no plugins 1`] = ` -
-
- -
- -
- -
-`; - -exports[`components/marketplace/ InstalledPlugins should render with one plugin 1`] = ` - -`; - -exports[`components/marketplace/ MarketplaceModal should render with error banner 1`] = ` - -
-
- +

+ App Marketplace +

+
+ } + inputSize="large" + name="searchMarketplaceTextbox" + onChange={[Function]} + onClear={[Function]} + placeholder="Search marketplace" + type="text" + useLegend={false} + value="" /> -
-
- - - + + `; -exports[`components/marketplace/ MarketplaceModal should render with no plugins installed 1`] = ` - - + +
+ + + + + + + + +
+ + + + -
-
+ + `; -exports[`components/marketplace/ MarketplaceModal should render with plugins installed 1`] = ` - - + + + + + - - + + +`; + +exports[`components/marketplace/ should render with plugins available 1`] = ` + + +
+ +
+

+ App Marketplace +

+
+ + } + inputSize="large" + name="searchMarketplaceTextbox" + onChange={[Function]} + onClear={[Function]} + placeholder="Search marketplace" + type="text" + useLegend={false} + value="" + /> +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+`; + +exports[`components/marketplace/ should render with plugins installed 1`] = ` + + +
+ +
+

+ App Marketplace +

+
+ + } + inputSize="large" + name="searchMarketplaceTextbox" + onChange={[Function]} + onClear={[Function]} + placeholder="Search marketplace" + type="text" + useLegend={false} + value="" + /> +
+ +
+ + + + + + + + +
+
+ + + +
+
+
`; diff --git a/webapp/channels/src/components/plugin_marketplace/index.ts b/webapp/channels/src/components/plugin_marketplace/index.ts deleted file mode 100644 index b004efae32..0000000000 --- a/webapp/channels/src/components/plugin_marketplace/index.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; -import {connect} from 'react-redux'; -import {bindActionCreators, Dispatch, ActionCreatorsMapObject} from 'redux'; - -import {GenericAction, ActionFunc} from 'mattermost-redux/types/actions'; - -import {GlobalState} from 'types/store'; -import {getListing, getInstalledListing} from 'selectors/views/marketplace'; -import {setFirstAdminVisitMarketplaceStatus} from 'mattermost-redux/actions/general'; -import {getPluginStatuses} from 'mattermost-redux/actions/admin'; -import {getFirstAdminVisitMarketplaceStatus} from 'mattermost-redux/selectors/entities/general'; - -import {makeAsyncComponent} from 'components/async_load'; - -import {isModalOpen} from 'selectors/views/modals'; -import {ModalIdentifiers} from 'utils/constants'; -import {getSiteURL} from 'utils/url'; - -import {closeModal} from 'actions/views/modals'; -import {fetchListing, filterListing} from 'actions/marketplace'; - -const MarketplaceModal = makeAsyncComponent('MarketplaceModal', React.lazy(() => import('./marketplace_modal'))); - -function mapStateToProps(state: GlobalState) { - return { - show: isModalOpen(state, ModalIdentifiers.PLUGIN_MARKETPLACE), - listing: getListing(state), - installedListing: getInstalledListing(state), - siteURL: getSiteURL(), - pluginStatuses: state.entities.admin.pluginStatuses, - firstAdminVisitMarketplaceStatus: getFirstAdminVisitMarketplaceStatus(state), - }; -} - -type Actions = { - closeModal(): void; - fetchListing(localOnly?: boolean): Promise<{error?: Error}>; - filterListing(filter: string): Promise<{error?: Error}>; - setFirstAdminVisitMarketplaceStatus(): Promise; - getPluginStatuses(): Promise; -} - -function mapDispatchToProps(dispatch: Dispatch) { - return { - actions: bindActionCreators, Actions>({ - closeModal: () => closeModal(ModalIdentifiers.PLUGIN_MARKETPLACE), - fetchListing, - filterListing, - setFirstAdminVisitMarketplaceStatus, - getPluginStatuses, - }, dispatch), - }; -} - -export default connect(mapStateToProps, mapDispatchToProps)(MarketplaceModal); diff --git a/webapp/channels/src/components/plugin_marketplace/marketplace_item/marketplace_item_app/__snapshots__/marketplace_item_app.test.tsx.snap b/webapp/channels/src/components/plugin_marketplace/marketplace_item/marketplace_item_app/__snapshots__/marketplace_item_app.test.tsx.snap index 1ec6de8134..7fb956f716 100644 --- a/webapp/channels/src/components/plugin_marketplace/marketplace_item/marketplace_item_app/__snapshots__/marketplace_item_app.test.tsx.snap +++ b/webapp/channels/src/components/plugin_marketplace/marketplace_item/marketplace_item_app/__snapshots__/marketplace_item_app.test.tsx.snap @@ -11,7 +11,7 @@ exports[`components/MarketplaceItemApp MarketplaceItem should render 1`] = ` } button={ + )} + + ) : ( +
+ {pageItems} +
+ )); +}; + +export default MarketplaceList; diff --git a/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/__snapshots__/navigation_row.test.tsx.snap b/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/__snapshots__/navigation_row.test.tsx.snap deleted file mode 100644 index f08718159d..0000000000 --- a/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/__snapshots__/navigation_row.test.tsx.snap +++ /dev/null @@ -1,157 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`components/marketplace/navigation_row should not render any buttons 1`] = ` -
-
-
- -
-
-
-`; - -exports[`components/marketplace/navigation_row should render next and previous buttons 1`] = ` -
-
- -
-
- -
-
- -
-
-`; - -exports[`components/marketplace/navigation_row should render only next button 1`] = ` -
-
-
- -
-
- -
-
-`; - -exports[`components/marketplace/navigation_row should render only previous button 1`] = ` -
-
- -
-
- -
-
-
-`; diff --git a/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/index.ts b/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/index.ts deleted file mode 100644 index 320c07dca9..0000000000 --- a/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {connect} from 'react-redux'; - -import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; -import {GlobalState} from '@mattermost/types/store'; - -import NavigationRow from './navigation_row'; - -function mapStateToProps(state: GlobalState) { - return { - theme: getTheme(state), - }; -} - -export default connect(mapStateToProps)(NavigationRow); diff --git a/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/navigation_button.tsx b/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/navigation_button.tsx deleted file mode 100644 index 8433739030..0000000000 --- a/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/navigation_button.tsx +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; -import {FormattedMessage} from 'react-intl'; - -type NavigationButtonProps = { - onClick: (event: React.MouseEvent) => void; - messageId: string; - defaultMessage: string; -}; - -export default class NavigationButton extends React.PureComponent { - onClick = (event: React.MouseEvent): void => { - event.preventDefault(); - this.props.onClick(event); - }; - - render(): JSX.Element { - const {onClick, messageId, defaultMessage} = this.props; - return ( - - ); - } -} diff --git a/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/navigation_row.test.tsx b/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/navigation_row.test.tsx deleted file mode 100644 index 4633263c55..0000000000 --- a/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/navigation_row.test.tsx +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; -import {shallow} from 'enzyme'; - -import {Theme} from 'mattermost-redux/selectors/entities/preferences'; - -import NavigationRow, {NavigationRowProps} from './navigation_row'; - -describe('components/marketplace/navigation_row', () => { - const baseProps: NavigationRowProps = { - page: 0, - total: 32, - maximumPerPage: 15, - onNextPageButtonClick: jest.fn(), - onPreviousPageButtonClick: jest.fn(), - theme: {centerChannelColor: '#fff'} as Theme, - }; - - it('should render only next button', () => { - const wrapper = shallow( - , - ); - - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('NavigationButton')).toHaveLength(1); - - wrapper.find('NavigationButton').simulate('click', {preventDefault: jest.fn}); - - expect(wrapper.instance().props.onNextPageButtonClick).toHaveBeenCalledTimes(1); - expect(wrapper.instance().props.onPreviousPageButtonClick).toHaveBeenCalledTimes(0); - }); - - it('should render next and previous buttons', () => { - const props = {...baseProps, page: 1}; - const wrapper = shallow( - , - ); - - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('NavigationButton')).toHaveLength(2); - - wrapper.find('NavigationButton').at(0).simulate('click', {preventDefault: jest.fn}); - wrapper.find('NavigationButton').at(1).simulate('click', {preventDefault: jest.fn}); - - expect(wrapper.instance().props.onNextPageButtonClick).toHaveBeenCalledTimes(1); - expect(wrapper.instance().props.onPreviousPageButtonClick).toHaveBeenCalledTimes(1); - }); - - it('should render only previous button', () => { - const props = {...baseProps, page: 2}; - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('NavigationButton')).toHaveLength(1); - - wrapper.find('NavigationButton').simulate('click', {preventDefault: jest.fn}); - - expect(wrapper.instance().props.onNextPageButtonClick).toHaveBeenCalledTimes(0); - expect(wrapper.instance().props.onPreviousPageButtonClick).toHaveBeenCalledTimes(1); - }); - - it('should not render any buttons', () => { - const props = {...baseProps, page: 0, total: 15}; - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('NavigationButton')).toHaveLength(0); - }); -}); diff --git a/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/navigation_row.tsx b/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/navigation_row.tsx deleted file mode 100644 index 98cff683d0..0000000000 --- a/webapp/channels/src/components/plugin_marketplace/marketplace_list/navigation_row/navigation_row.tsx +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; -import {FormattedMessage} from 'react-intl'; - -import {Theme} from 'mattermost-redux/selectors/entities/preferences'; -import {changeOpacity, makeStyleFromTheme} from 'mattermost-redux/utils/theme_utils'; - -import NavigationButton from './navigation_button'; - -export type NavigationRowProps = { - page: number; - total: number; - maximumPerPage: number; - onNextPageButtonClick: (event: React.MouseEvent) => void; - onPreviousPageButtonClick: (event: React.MouseEvent) => void; - theme: Theme; -}; - -export default class NavigationRow extends React.PureComponent { - canShowNextButton = (): boolean => { - const {page, maximumPerPage, total} = this.props; - const totalPages = Math.trunc((total - 1) / maximumPerPage); - - return totalPages > page; - }; - - renderCount = (): JSX.Element => { - const {page, total, maximumPerPage} = this.props; - const startCount = page * maximumPerPage; - const endCount = Math.min(startCount + maximumPerPage, total); - - return ( - - ); - }; - - render(): JSX.Element { - const style = getStyle(this.props.theme); - - return ( -
-
- {(this.props.page > 0) && ( - - )} -
-
- {this.renderCount()} -
-
- {this.canShowNextButton() && ( - - )} -
-
- ); - } -} - -const getStyle = makeStyleFromTheme((theme) => { - return { - count: { - color: changeOpacity(theme.centerChannelColor, 0.6), - }, - }; -}); diff --git a/webapp/channels/src/components/plugin_marketplace/marketplace_modal.scss b/webapp/channels/src/components/plugin_marketplace/marketplace_modal.scss index f2f3dec629..5a0495c0fc 100644 --- a/webapp/channels/src/components/plugin_marketplace/marketplace_modal.scss +++ b/webapp/channels/src/components/plugin_marketplace/marketplace_modal.scss @@ -1,21 +1,11 @@ @import 'utils/variables'; +@import 'utils/mixins'; -.modal-marketplace { - display: flex; - width: 100%; - height: 100%; - flex-direction: column; - align-items: center; - padding-top: 50px; - color: var(--center-channel-color); - font-size: 16px; - - @media (max-width: 768px) { - padding-right: 15px; - padding-left: 15px; - } +.marketplace-modal { + width: 800px; div.navigation-row { + overflow: unset; margin-top: 10px; div { @@ -29,7 +19,7 @@ } div.count { - padding-top: 8px; + padding: 9px 15px; } } @@ -45,33 +35,47 @@ } .nav-tabs { - font-size: 14px; + padding: 0 32px; + margin: 0 0 8px; - > li { - > a { - padding: 10px 16px; + li { + margin-right: 0; + + a { + padding: 13px 12px; + border: none; background: transparent; + color: rgba(var(--center-channel-color-rgb), 0.64); + font-size: 14px; + font-weight: 600; + line-height: 20px; transition: all 0.15s ease; &:hover, &:active, - &:focus { + &:focus, + &:focus-within { + border: none; background: transparent; + border-radius: none; color: var(--center-channel-color); } } - &.active > a { - color: var(--center-channel-color); + &.active { + border-bottom: 2px solid var(--denim-button-bg); + + a { + color: var(--denim-button-bg); + } + } + + &:not(:first-child) { + margin-left: 8px; } } } - h1 { - margin: 8px 0 24px; - font-size: 28px; - } - h2 { font-weight: 300; @@ -81,8 +85,14 @@ } .more-modal__list { + height: 390px; + margin: 0 6px 8px 12px; + overflow-y: scroll; + .more-modal__row { - align-items: normal; + min-height: 80px; + padding: 16px 20px; + border-bottom: none; .marketplace__tag { margin-left: 6px; @@ -94,25 +104,91 @@ margin: 10px 10px 0 0; font-size: 0.9em; } + + .more-modal__details { + padding-left: 16px; + + .more-modal__row--link { + color: var(--center-channel-color); + font-size: 16px; + font-weight: 600; + line-height: 24px; + } + + .more-modal__description { + margin: 2px 0 0; + color: rgba(var(--center-channel-color-rgb), 0.64); + font-size: 14px; + font-weight: 400; + line-height: 20px; + } + } + + .more-modal__actions { + padding-left: 16px; + margin: 0; + + .plugin-configure, + .app-installed { + @include secondary-button; + @include button-medium; + } + + .plugin-install, + .app-install { + @include primary-button; + @include button-medium; + } + + a { + &:hover, + &:focus { + text-decoration: none; + } + } + } + + &:hover, + &:focus, + &:focus-within { + background-color: rgba(var(--center-channel-color-rgb), 0.08); + } } - .more-modal__description { - margin: 2px 0 0; - font-size: 0.9em; - } + .icon__plugin { + display: flex; + height: 48px; + flex: 0 0 48px; + align-items: center; + justify-content: center; + background-color: $white; + border-radius: 50%; - padding-bottom: 80px; + svg, + img { + width: 48px; + height: 48px; + } + + svg { + fill: var(--button-bg); + } + + img { + border-radius: 4px; + } + } } - .search_input { - width: 720px; - height: 40px; - flex: 1; - margin-top: 28px; - margin-right: 16px; - margin-bottom: 20px; - margin-left: 16px; - box-shadow: none; + .marketplace-modal-search { + padding: 24px 0 0; + + .search_input { + width: 100%; + border: 0 !important; + border-radius: 0 !important; + box-shadow: none; + } } .btn { @@ -130,8 +206,9 @@ .tabs { display: flex; - width: 720px; + width: 100%; flex-direction: column; + margin-top: 12px; } .subtitle { @@ -160,67 +237,41 @@ } } - .icon__plugin { + .no_plugins { display: flex; - height: 42px; - flex: 0 0 42px; + height: 390px; + flex-flow: column; align-items: center; justify-content: center; - margin-right: 4px; - border-radius: 50%; + margin-bottom: 8px; - svg { - width: 32px; - height: 32px; - fill: var(--button-bg); + &__message { + margin-top: 20px; + color: var(--center-channel-color); + font-size: 20px; + font-weight: 600; + line-height: 28px; } - } - .icon__plugin--background { - padding: 6px; - background-color: $white; + &__action { + @include primary-button; + @include button-medium; - svg { - width: 24px; - height: 24px; + margin-top: 30px; } - } - .no_plugins_div { - text-align: center; + .icon__plugin { + svg { + fill: var(--button-bg); + } + } } .item_error { - background-color: rgba(var(--error-text-rgb), 0.08); + background-color: rgba(var(--error-text-color-rgb), 0.08); } - .error_text { - color: var(--error-text); - opacity: 1; - } -} - -.error-bar { - position: fixed; - z-index: 8; - top: 0; - overflow: hidden; - width: 100%; - min-height: $announcement-bar-height; - max-height: $announcement-bar-height; - padding: 5px 30px; - background-color: var(--center-channel-bg); - color: var(--error-text); - - .error-bar__content { - position: absolute; - top: 0; - left: 0; - display: flex; - width: 100%; - height: 100%; - align-items: center; - justify-content: center; - background-color: rgba(var(--error-text-rgb), 0.12); + .loading { + height: 390px; } } diff --git a/webapp/channels/src/components/plugin_marketplace/marketplace_modal.test.tsx b/webapp/channels/src/components/plugin_marketplace/marketplace_modal.test.tsx index 3e2938603c..c4c2181182 100644 --- a/webapp/channels/src/components/plugin_marketplace/marketplace_modal.test.tsx +++ b/webapp/channels/src/components/plugin_marketplace/marketplace_modal.test.tsx @@ -5,19 +5,21 @@ import React from 'react'; import {shallow} from 'enzyme'; import {AuthorType, MarketplacePlugin, ReleaseStage} from '@mattermost/types/marketplace'; -import type {PluginStatusRedux} from '@mattermost/types/plugins'; -import {trackEvent} from 'actions/telemetry_actions.jsx'; +import {ActionFunc} from 'mattermost-redux/types/actions'; -import MarketplaceModal, {AllListing, InstalledListing, MarketplaceModalProps} from './marketplace_modal'; +import {GlobalState} from 'types/store'; +import {ModalIdentifiers} from 'utils/constants'; -jest.mock('actions/telemetry_actions.jsx', () => { - const original = jest.requireActual('actions/telemetry_actions.jsx'); - return { - ...original, - trackEvent: jest.fn(), - }; -}); +import MarketplaceModal, {OpenedFromType} from './marketplace_modal'; + +let mockState: GlobalState; + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux') as typeof import('react-redux'), + useSelector: (selector: (state: typeof mockState) => unknown) => selector(mockState), + useDispatch: jest.fn(() => (action: ActionFunc) => action), +})); describe('components/marketplace/', () => { const samplePlugin: MarketplacePlugin = { @@ -52,161 +54,106 @@ describe('components/marketplace/', () => { installed_version: '1.0.3', }; - describe('AllListing', () => { - it('should render with no plugins', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); - }); + const defaultProps = { + openedFrom: 'actions_menu' as OpenedFromType, + }; - it('should render with one plugin', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); - }); - - it('should render with plugins', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('InstalledPlugins', () => { - const baseProps = { - changeTab: jest.fn(), - }; - - it('should render with no plugins', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); - }); - - it('should render with one plugin', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); - }); - - it('should render with multiple plugins', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('MarketplaceModal', () => { - const baseProps: MarketplaceModalProps = { - show: true, - listing: [samplePlugin], - installedListing: [], - pluginStatuses: {}, - siteURL: 'http://example.com', - firstAdminVisitMarketplaceStatus: false, - openedFrom: 'actions_menu', - actions: { - closeModal: jest.fn(), - fetchListing: jest.fn(() => { - return Promise.resolve({}); - }), - filterListing: jest.fn(() => { - return Promise.resolve({}); - }), - setFirstAdminVisitMarketplaceStatus: jest.fn(), - getPluginStatuses: jest.fn(), + beforeEach(() => { + mockState = { + views: { + modals: { + modalState: { + [ModalIdentifiers.PLUGIN_MARKETPLACE]: { + open: true, + }, + }, + }, + marketplace: { + plugins: [], + apps: [], + }, }, - }; + entities: { + general: { + firstAdminCompleteSetup: false, + }, + admin: { + pluginStatuses: {}, + }, + }, + } as unknown as GlobalState; + }); - test('should render with no plugins installed', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); - }); + test('should render default', () => { + const wrapper = shallow( + , + ); - test('should render with plugins installed', () => { - const props = { - ...baseProps, - plugins: [ - ...baseProps.listing, - sampleInstalledPlugin, - ], - installedListing: [ - sampleInstalledPlugin, - ], - }; + expect(wrapper.shallow()).toMatchSnapshot(); + }); - const wrapper = shallow( - , - ); + test('should render with no plugins available', () => { + const setState = jest.fn(); + const useStateSpy = jest.spyOn(React, 'useState'); + useStateSpy.mockImplementationOnce(() => [false, setState]); - expect(wrapper).toMatchSnapshot(); - }); + const wrapper = shallow( + , + ); - test('should fetch plugins when plugin status is changed', () => { - const fetchListing = baseProps.actions.fetchListing; - const wrapper = shallow(); + wrapper.update(); - expect(fetchListing).toBeCalledTimes(1); - wrapper.setProps({...baseProps}); - expect(fetchListing).toBeCalledTimes(1); + expect(wrapper.shallow()).toMatchSnapshot(); + }); - const status = { - id: 'test', - } as PluginStatusRedux; - wrapper.setProps({...baseProps, pluginStatuses: {test: status}}); - expect(fetchListing).toBeCalledTimes(2); - }); + test('should render with plugins available', () => { + const setState = jest.fn(); + const useStateSpy = jest.spyOn(React, 'useState'); + useStateSpy.mockImplementationOnce(() => [false, setState]); - test('should render with error banner', () => { - const wrapper = shallow( - , - ); + mockState.views.marketplace.plugins = [ + samplePlugin, + ]; - wrapper.setState({serverError: {name: 'some.error', message: 'Error test'}}); + const wrapper = shallow( + , + ); - expect(wrapper).toMatchSnapshot(); - }); + wrapper.update(); - test('Should call for track event when searching', () => { - const wrapper = shallow( - , - ); + expect(wrapper.shallow()).toMatchSnapshot(); + }); - wrapper.setState({filter: 'nps'}); - wrapper.instance().doSearch(); + test('should render with plugins installed', () => { + const setState = jest.fn(); + const useStateSpy = jest.spyOn(React, 'useState'); + useStateSpy.mockImplementationOnce(() => [false, setState]); - expect(trackEvent).toHaveBeenCalledWith('plugins', 'ui_marketplace_opened', {from: 'actions_menu'}); - expect(trackEvent).toHaveBeenCalledWith('plugins', 'ui_marketplace_search', {filter: 'nps'}); - }); + mockState.views.marketplace.plugins = [ + samplePlugin, + sampleInstalledPlugin, + ]; - test('Should call for opened track event on mount', () => { - const openedFrom = 'actions_menu'; + const wrapper = shallow( + , + ); - shallow( - , - ); + wrapper.update(); - expect(trackEvent).toHaveBeenCalledWith('plugins', 'ui_marketplace_opened', {from: openedFrom}); - }); + expect(wrapper.shallow()).toMatchSnapshot(); + }); + + test('should render with error banner', () => { + const setState = jest.fn(); + const useStateSpy = jest.spyOn(React, 'useState'); + useStateSpy.mockImplementation(() => [true, setState]); + + const wrapper = shallow( + , + ); + + wrapper.update(); + + expect(wrapper.shallow()).toMatchSnapshot(); }); }); diff --git a/webapp/channels/src/components/plugin_marketplace/marketplace_modal.tsx b/webapp/channels/src/components/plugin_marketplace/marketplace_modal.tsx index 59ac7510ba..062727f9e1 100644 --- a/webapp/channels/src/components/plugin_marketplace/marketplace_modal.tsx +++ b/webapp/channels/src/components/plugin_marketplace/marketplace_modal.tsx @@ -1,283 +1,269 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; -import {FormattedMessage} from 'react-intl'; -import debounce from 'lodash/debounce'; +import React, {useCallback, useEffect, useRef, useState} from 'react'; import {Tabs, Tab, SelectCallback} from 'react-bootstrap'; +import {useIntl} from 'react-intl'; +import {useDispatch, useSelector} from 'react-redux'; +import {Link} from 'react-router-dom'; +import debounce from 'lodash/debounce'; -import {PluginStatusRedux} from '@mattermost/types/plugins'; -import type {MarketplaceApp, MarketplacePlugin} from '@mattermost/types/marketplace'; +import {MagnifyIcon} from '@mattermost/compass-icons/components'; -import FullScreenModal from 'components/widgets/modals/full_screen_modal'; -import RootPortal from 'components/root_portal'; -import QuickInput from 'components/quick_input'; -import LocalizedInput from 'components/localized_input/localized_input'; -import PluginIcon from 'components/widgets/icons/plugin_icon'; -import LoadingScreen from 'components/loading_screen'; -import FormattedMarkdownMessage from 'components/formatted_markdown_message'; +import {FooterPagination} from '@mattermost/components'; +import {getPluginStatuses} from 'mattermost-redux/actions/admin'; +import {setFirstAdminVisitMarketplaceStatus} from 'mattermost-redux/actions/general'; +import {getFirstAdminVisitMarketplaceStatus} from 'mattermost-redux/selectors/entities/general'; +import {ActionResult} from 'mattermost-redux/types/actions'; +import {fetchListing, filterListing} from 'actions/marketplace'; import {trackEvent} from 'actions/telemetry_actions.jsx'; -import {t} from 'utils/i18n'; -import {localizeMessage} from 'utils/utils'; +import {closeModal} from 'actions/views/modals'; + +import GenericModal from 'components/generic_modal'; +import LoadingScreen from 'components/loading_screen'; +import Input, {SIZE} from 'components/widgets/inputs/input/input'; + +import {getListing, getInstalledListing} from 'selectors/views/marketplace'; +import {isModalOpen} from 'selectors/views/modals'; +import {GlobalState} from 'types/store'; +import {ModalIdentifiers} from 'utils/constants'; import './marketplace_modal.scss'; -import MarketplaceList from './marketplace_list/marketplace_list'; + +import MarketplaceList, {ITEMS_PER_PAGE} from './marketplace_list/marketplace_list'; const MarketplaceTabs = { - ALL_LISTING: 'allListing', + ALL_LISTING: 'all', INSTALLED_LISTING: 'installed', }; const SEARCH_TIMEOUT_MILLISECONDS = 200; +const linkConsole = (msg: string) => ( + + {msg} + +); + export type OpenedFromType = 'actions_menu' | 'app_bar' | 'channel_header' | 'command' | 'open_plugin_install_post' | 'product_menu'; -type AllListingProps = { - listing: Array; -}; - -// AllListing renders the contents of the all listing tab. -export const AllListing = ({listing}: AllListingProps): JSX.Element => { - if (listing.length === 0) { - return ( -
-
- -
- -
-
- ); - } - - return ; -}; - -type InstalledListingProps = { - installedItems: Array; - changeTab: SelectCallback; -}; - -// InstalledListing renders the contents of the installed listing tab. -export const InstalledListing = ({installedItems, changeTab}: InstalledListingProps): JSX.Element => { - if (installedItems.length === 0) { - return ( -
-
- -
- -
- -
- ); - } - - return ; -}; - -export type MarketplaceModalProps = { - show: boolean; - listing: Array; - installedListing: Array; - siteURL: string; - pluginStatuses?: Record; - firstAdminVisitMarketplaceStatus: boolean; +type MarketplaceModalProps = { openedFrom: OpenedFromType; - actions: { - closeModal: () => void; - fetchListing(localOnly?: boolean): Promise<{error?: Error}>; - filterListing(filter: string): Promise<{error?: Error}>; - setFirstAdminVisitMarketplaceStatus(): Promise; - getPluginStatuses(): Promise; - }; -}; - -type MarketplaceModalState = { - tabKey: unknown; - loading: boolean; - serverError?: Error; - filter: string; -}; - -// MarketplaceModal is the marketplace modal. -export default class MarketplaceModal extends React.PureComponent { - private filterRef: React.RefObject; - - constructor(props: MarketplaceModalProps) { - super(props); - - this.state = { - tabKey: MarketplaceTabs.ALL_LISTING, - loading: true, - serverError: undefined, - filter: '', - }; - - this.filterRef = React.createRef(); - } - - componentDidMount(): void { - trackEvent('plugins', 'ui_marketplace_opened', {from: this.props.openedFrom}); - - this.fetchListing(); - this.props.actions.getPluginStatuses(); - if (!this.props.firstAdminVisitMarketplaceStatus) { - trackEvent('plugins', 'ui_first_admin_visit_marketplace_status'); - - this.props.actions.setFirstAdminVisitMarketplaceStatus(); - } - - this.filterRef.current?.focus(); - } - - componentDidUpdate(prevProps: MarketplaceModalProps): void { - // Automatically refresh the component when a plugin is installed or uninstalled. - if (this.props.pluginStatuses !== prevProps.pluginStatuses) { - this.fetchListing(); - } - } - - fetchListing = async (): Promise => { - const {error} = await this.props.actions.fetchListing(); - this.setState({loading: false, serverError: error}); - } - - close = (): void => { - trackEvent('plugins', 'ui_marketplace_closed'); - this.props.actions.closeModal(); - } - - changeTab: SelectCallback = (tabKey: any): void => { - this.setState({tabKey}); - } - - onInput = (): void => { - if (this.filterRef.current) { - this.setState({filter: this.filterRef.current.value}); - - this.debouncedSearch(); - } - } - - handleClearSearch = (): void => { - if (this.filterRef.current) { - this.filterRef.current.value = ''; - this.setState({filter: this.filterRef.current.value}, this.doSearch); - } - } - - doSearch = async (): Promise => { - trackEvent('plugins', 'ui_marketplace_search', {filter: this.state.filter}); - - const {error} = await this.props.actions.filterListing(this.state.filter); - - this.setState({serverError: error}); - } - - debouncedSearch = debounce(this.doSearch, SEARCH_TIMEOUT_MILLISECONDS); - - render(): JSX.Element { - const input = ( -
-
- -
-
- ); - - let errorBanner = null; - if (this.state.serverError) { - errorBanner = ( -
-
- -
-
- ); - } - - return ( - - - {errorBanner} - - - - ); - } } + +const MarketplaceModal = ({ + openedFrom, +}: MarketplaceModalProps) => { + const dispatch = useDispatch(); + const {formatMessage} = useIntl(); + const listRef = useRef(null); + + const show = useSelector((state: GlobalState) => isModalOpen(state, ModalIdentifiers.PLUGIN_MARKETPLACE)); + const listing = useSelector(getListing); + const installedListing = useSelector(getInstalledListing); + const pluginStatuses = useSelector((state: GlobalState) => state.entities.admin.pluginStatuses); + const hasFirstAdminVisitedMarketplace = useSelector(getFirstAdminVisitMarketplaceStatus); + + const [tabKey, setTabKey] = useState(MarketplaceTabs.ALL_LISTING); + const [filter, setFilter] = useState(''); + const [page, setPage] = useState(0); + const [hasLoaded, setHasLoaded] = useState(false); + const [loading, setLoading] = React.useState(true); + const [serverError, setServerError] = React.useState(false); + + const doFetchListing = useCallback(async () => { + const {error} = await dispatch(fetchListing()) as ActionResult; + + if (error) { + setServerError(true); + } + + setLoading(false); + }, []); + + const doSearch = useCallback(async () => { + trackEvent('plugins', 'ui_marketplace_search', {filter}); + + const {error} = await dispatch(filterListing(filter)) as ActionResult; + + if (error) { + setServerError(true); + } + }, [filter]); + + const debouncedSearch = debounce(doSearch, SEARCH_TIMEOUT_MILLISECONDS); + + useEffect(() => { + async function doFetch() { + await dispatch(getPluginStatuses()); + await doFetchListing(); + setHasLoaded(true); + } + + trackEvent('plugins', 'ui_marketplace_opened', {from: openedFrom}); + + if (!hasFirstAdminVisitedMarketplace) { + trackEvent('plugins', 'ui_first_admin_visit_marketplace_status'); + dispatch(setFirstAdminVisitMarketplaceStatus()); + } + + doFetch(); + }, []); + + useEffect(() => { + if (hasLoaded) { + doFetchListing(); + } + }, [pluginStatuses]); + + useEffect(() => { + if (hasLoaded) { + debouncedSearch(); + setPage(0); + } + }, [filter]); + + const scrollListToTop = useCallback(() => { + if (listRef.current) { + listRef.current.scrollTop = 0; + } + }, []); + + const handleOnClose = () => { + trackEvent('plugins', 'ui_marketplace_closed'); + dispatch(closeModal(ModalIdentifiers.PLUGIN_MARKETPLACE)); + }; + + const handleChangeTab: SelectCallback = useCallback((tabKey) => { + setTabKey(tabKey); + setPage(0); + scrollListToTop(); + }, [scrollListToTop]); + + const handleOnChange = useCallback((event: React.ChangeEvent) => { + setFilter(event.target.value); + }, []); + + const handleOnClear = useCallback(() => { + setFilter(''); + }, []); + + const handleOnNextPage = useCallback(() => { + setPage(page + 1); + scrollListToTop(); + }, [page, scrollListToTop]); + + const handleOnPreviousPage = useCallback(() => { + setPage(page - 1); + scrollListToTop(); + }, [page, scrollListToTop]); + + const handleNoResultsButtonClick = useCallback(() => { + handleChangeTab(MarketplaceTabs.ALL_LISTING); + }, [handleChangeTab]); + + const getHeaderInput = useCallback(() => ( + } + placeholder={formatMessage({id: 'marketplace_modal.search', defaultMessage: 'Search marketplace'})} + useLegend={false} + autoFocus={true} + clearable={true} + value={filter} + onChange={handleOnChange} + onClear={handleOnClear} + /> + ), [filter, handleOnChange, handleOnClear]); + + const getFooterContent = useCallback(() => ( + + ), [installedListing.length, listing.length, page, handleOnNextPage, handleOnPreviousPage, tabKey]); + + return ( + System Console.', + }, + {linkConsole}, + ) + ) : undefined} + show={show} + compassDesign={true} + bodyPadding={false} + footerDivider={true} + onExited={handleOnClose} + footerContent={getFooterContent()} + headerInput={getHeaderInput()} + > + + + {loading ? ( + + ) : ( + + )} + + + + + + + ); +}; + +export default MarketplaceModal; diff --git a/webapp/channels/src/components/product_notices_modal/__snapshots__/product_notices.test.tsx.snap b/webapp/channels/src/components/product_notices_modal/__snapshots__/product_notices.test.tsx.snap index abebd8539b..5252df431b 100644 --- a/webapp/channels/src/components/product_notices_modal/__snapshots__/product_notices.test.tsx.snap +++ b/webapp/channels/src/components/product_notices_modal/__snapshots__/product_notices.test.tsx.snap @@ -4,6 +4,7 @@ exports[`ProductNoticesModal Match snapshot for single notice 1`] = ` +
+ +
+ +
+
+
+`; diff --git a/webapp/channels/src/components/widgets/inputs/input/input.scss b/webapp/channels/src/components/widgets/inputs/input/input.scss index 281c31175f..eacee3bfba 100644 --- a/webapp/channels/src/components/widgets/inputs/input/input.scss +++ b/webapp/channels/src/components/widgets/inputs/input/input.scss @@ -49,11 +49,16 @@ .Input_wrapper { display: flex; flex: 1; + align-items: center; padding: 0 16px; margin: 2px 0; color: rgba(var(--center-channel-color-rgb), 0.56); font-size: 14px; line-height: 20px; + + > :not(:first-child) { + margin-left: 8px; + } } .Input_limit-exceeded { @@ -196,4 +201,10 @@ background-color: rgba(var(--center-channel-color-rgb), 0.04); } } + + .Input__clear { + display: flex; + color: rgba(var(--center-channel-color), 0.68); + cursor: pointer; + } } diff --git a/webapp/channels/src/components/widgets/inputs/input/input.test.tsx b/webapp/channels/src/components/widgets/inputs/input/input.test.tsx new file mode 100644 index 0000000000..b77523ba2f --- /dev/null +++ b/webapp/channels/src/components/widgets/inputs/input/input.test.tsx @@ -0,0 +1,48 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {mount, shallow} from 'enzyme'; +import React from 'react'; + +import OverlayTrigger from 'components/overlay_trigger'; + +import Input from './input'; + +describe('components/widgets/inputs/Input', () => { + test('should match snapshot', () => { + const wrapper = shallow( + , + ); + + expect(wrapper).toMatchSnapshot(); + }); + + test('should render with clearable enabled', () => { + const value = 'value'; + const clearableTooltipText = 'tooltip text'; + const onClear = jest.fn(); + + const wrapper = shallow( + , + ); + + const clear = wrapper.find('.Input__clear'); + expect(clear.length).toEqual(1); + expect(wrapper.find('CloseCircleIcon').length).toEqual(1); + + const tooltip = wrapper.find(OverlayTrigger); + expect(tooltip.length).toEqual(1); + + const overlay = mount(tooltip.prop('overlay')); + expect(overlay.text()).toEqual(clearableTooltipText); + + clear.first().simulate('mousedown'); + + expect(onClear).toHaveBeenCalledTimes(1); + }); +}); diff --git a/webapp/channels/src/components/widgets/inputs/input/input.tsx b/webapp/channels/src/components/widgets/inputs/input/input.tsx index 1a55dbb9f4..bcc66e4a20 100644 --- a/webapp/channels/src/components/widgets/inputs/input/input.tsx +++ b/webapp/channels/src/components/widgets/inputs/input/input.tsx @@ -3,10 +3,14 @@ import React, {useState, useEffect} from 'react'; import {useIntl} from 'react-intl'; - import classNames from 'classnames'; -import {ItemStatus} from 'utils/constants'; +import {CloseCircleIcon} from '@mattermost/compass-icons/components'; + +import OverlayTrigger from 'components/overlay_trigger'; +import Tooltip from 'components/tooltip'; + +import Constants, {ItemStatus} from 'utils/constants'; import './input.scss'; @@ -32,6 +36,9 @@ interface InputProps extends React.InputHTMLAttributes { useLegend?: boolean; customMessage?: CustomMessageInputType; inputSize?: SIZE; + clearable?: boolean; + clearableTooltipText?: string; + onClear?: () => void; } const Input = React.forwardRef(( @@ -56,9 +63,12 @@ const Input = React.forwardRef(( maxLength, inputSize = SIZE.MEDIUM, disabled, + clearable, + clearableTooltipText, onFocus, onBlur, onChange, + onClear, ...otherProps }: InputProps, ref?: React.Ref, @@ -109,6 +119,12 @@ const Input = React.forwardRef(( } }; + const handleOnClear = () => { + if (onClear) { + onClear(); + } + }; + const validateInput = () => { if (!required || (value !== null && value !== '')) { return; @@ -121,6 +137,26 @@ const Input = React.forwardRef(( const error = customInputLabel?.type === 'error'; const limitExceeded = limit && value && !Array.isArray(value) ? value.toString().length - limit : 0; + const clearButton = value && clearable ? ( +
+ + {clearableTooltipText || formatMessage({id: 'widget.input.clear', defaultMessage: 'Clear'})} + + )} + > + + +
+ ) : null; + return (
)} {inputSuffix} + {clearButton}
{addon} diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index b6cdf2c336..e273515c5a 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -2652,7 +2652,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} removed the channel purpose (was: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} updated the channel purpose from: {old} to: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} updated the channel purpose to: {new}", - "app.plugin.marketplace_plugins.app_error": "Error connecting to the marketplace server. Please check your settings in the [System Console]({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Error: {error}", "apps.error.command.field_missing": "Required fields missing: `{fieldName}`.", "apps.error.command.same_channel": "Channel repeated for field `{fieldName}`: `{option}`.", @@ -3441,6 +3440,9 @@ "filtered_user_list.userStatus": "User Status:", "flag_post.flag": "Save", "flag_post.unflag": "Remove from Saved", + "footer_pagination.count": "Showing {startCount, number}-{endCount, number} of {total, number}", + "footer_pagination.next": "Next", + "footer_pagination.prev": "Previous", "forward_post_button.label": "Forward", "forward_post_modal.button.cancel": "Cancel", "forward_post_modal.button.forward": "Forward", @@ -4085,8 +4087,9 @@ "mark_all_threads_as_read_modal.title": "Mark all your threads as read?", "marketplace_command.disabled": "The marketplace is disabled. Please contact your System Administrator for details.", "marketplace_command.no_permission": "You do not have the appropriate permissions to access the marketplace.", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {plugins}} of {total, number} total", - "marketplace_modal.install_plugins": "Install Plugins", + "marketplace_modal_list.no_plugins_filter": "No results for \"{filter}\"", + "marketplace_modal.app_error": "Error connecting to the marketplace server. Please check your settings in the System Console.", + "marketplace_modal.install_plugins": "Install plugins", "marketplace_modal.installing": "Installing...", "marketplace_modal.list.configure": "Configure", "marketplace_modal.list.configure.plugin": "Configure {plugin}", @@ -4103,12 +4106,12 @@ "marketplace_modal.list.update_confirmation.message.warning_major_version": "This update may contain breaking changes.", "marketplace_modal.list.update_confirmation.message.warning_major_version_with_release_notes": "This update may contain breaking changes. Consult the [release notes](!{releaseNotesUrl}) before upgrading.", "marketplace_modal.list.update_confirmation.title": "Confirm Plugin Update", - "marketplace_modal.no_plugins": "There are no plugins available at this time.", - "marketplace_modal.no_plugins_installed": "You do not have any plugins installed.", - "marketplace_modal.search": "Search Marketplace", + "marketplace_modal.no_plugins": "No plugins found", + "marketplace_modal.no_plugins_installed": "No plugins installed found", + "marketplace_modal.search": "Search marketplace", "marketplace_modal.tabs.all_listing": "All", - "marketplace_modal.tabs.installed_listing": "Installed", - "marketplace_modal.title": "Marketplace", + "marketplace_modal.tabs.installed_listing": "Installed ({count})", + "marketplace_modal.title": "App Marketplace", "members_popover.button.message": "message", "menu.cloudFree.enterpriseTrialDescription": "Your trial is active until {trialEndDay}. Discover our top Enterprise features. Learn more", "menu.cloudFree.enterpriseTrialTitle": "Enterprise Trial", @@ -5676,6 +5679,7 @@ "welcome_post_renderer.user_message.first_paragraph": "Mattermost is an open source platform for secure communication, collaboration, and orchestration of work across tools and teams.", "welcome_post_renderer.user_message.second_paragraph": "Here is a list of commands to use to try and get familiar with the platform.", "welcome_post_renderer.user_message.title": "Welcome to Mattermost! :rocket:", + "widget.input.clear": "Clear", "widget.input.required": "This field is required", "widget.passwordInput.createPassword": "Choose a Password", "widget.passwordInput.password": "Password", diff --git a/webapp/channels/src/sass/utils/_mixins.scss b/webapp/channels/src/sass/utils/_mixins.scss index 2d3f74df34..bb4ef5b0a0 100644 --- a/webapp/channels/src/sass/utils/_mixins.scss +++ b/webapp/channels/src/sass/utils/_mixins.scss @@ -114,9 +114,13 @@ display: flex; font-size: 18px; - &::before { + &:first-child::before { margin: 0 7px 0 0; } + + &:last-child::before { + margin: 0 0 0 7px; + } } } @@ -146,7 +150,7 @@ outline: none; } - &:disabled { + &:disabled:not(.always-show-enabled) { background: rgba(var(--center-channel-color-rgb), 0.08); color: rgba(var(--center-channel-color-rgb), 0.32); cursor: not-allowed; diff --git a/webapp/platform/components/src/generic_modal/footer_content/__snapshots__/footer_pagination.test.tsx.snap b/webapp/platform/components/src/generic_modal/footer_content/__snapshots__/footer_pagination.test.tsx.snap new file mode 100644 index 0000000000..29d49c0a2a --- /dev/null +++ b/webapp/platform/components/src/generic_modal/footer_content/__snapshots__/footer_pagination.test.tsx.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/GenericModal/FooterPagination should render default 1`] = ` +
+
+
+ + +
+
+`; diff --git a/webapp/platform/components/src/generic_modal/footer_content/footer_pagination.scss b/webapp/platform/components/src/generic_modal/footer_content/footer_pagination.scss new file mode 100644 index 0000000000..35594f8bc5 --- /dev/null +++ b/webapp/platform/components/src/generic_modal/footer_content/footer_pagination.scss @@ -0,0 +1,41 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +@import '../../../../../channels/src/sass/utils/mixins'; + +.footer-pagination { + display: flex; + flex: 1; + flex-direction: row; + align-items: center; + + &__legend { + display: flex; + flex: 1; + align-items: center; + justify-content: flex-start; + color: rgba(var(--center-channel-color-rgb), 0.64); + font-size: 12px; + font-weight: 600; + line-height: 16px; + } + + &__button-container { + display: flex; + align-items: center; + justify-content: center; + + &__button { + @include tertiary-button; + @include button-small; + + &:not(:first-child) { + margin-left: 8px; + } + + > :not(:first-child) { + margin-left: 5px; + } + } + } +} diff --git a/webapp/platform/components/src/generic_modal/footer_content/footer_pagination.test.tsx b/webapp/platform/components/src/generic_modal/footer_content/footer_pagination.test.tsx new file mode 100644 index 0000000000..9b80d2a2fe --- /dev/null +++ b/webapp/platform/components/src/generic_modal/footer_content/footer_pagination.test.tsx @@ -0,0 +1,88 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {shallow} from 'enzyme'; + +import {FooterPagination} from './'; + +describe('components/GenericModal/FooterPagination', () => { + const baseProps = { + page: 0, + total: 0, + itemsPerPage: 0, + onNextPage: jest.fn(), + onPreviousPage: jest.fn(), + }; + + test('should render default', () => { + const wrapper = shallow( + , + ); + + expect(wrapper).toMatchSnapshot(); + }); + + test('should render pagination legend', () => { + const wrapper = shallow( + , + ); + + const legend = wrapper.find('.footer-pagination__legend'); + + expect(legend.length).toEqual(1); + expect(legend.at(0).text()).toEqual('Showing 1-10 of 17'); + }); + + test('should render pagination buttons', () => { + const wrapper = shallow( + , + ); + + const buttons = wrapper.find('.footer-pagination__button-container__button'); + + expect(buttons.length).toEqual(2); + expect(buttons.at(0).text()).toEqual('Previous'); + expect(buttons.at(1).text()).toEqual('Next'); + }); + + test('should handle pagination buttons', async () => { + const onPreviousPage = jest.fn(); + const onNextPage = jest.fn(); + + const wrapper = shallow( + , + ); + + const buttons = wrapper.find('.footer-pagination__button-container__button'); + const prevButton = buttons.at(0); + const nextButton = buttons.at(1); + + expect(prevButton.hasClass('disabled')).toBeFalsy(); + expect(nextButton.hasClass('disabled')).toBeFalsy(); + + nextButton.simulate('click'); + + expect(onNextPage).toHaveBeenCalledTimes(1); + + prevButton.simulate('click'); + + expect(onPreviousPage).toHaveBeenCalledTimes(1); + }); +}); diff --git a/webapp/platform/components/src/generic_modal/footer_content/footer_pagination.tsx b/webapp/platform/components/src/generic_modal/footer_content/footer_pagination.tsx new file mode 100644 index 0000000000..3efd3c7a75 --- /dev/null +++ b/webapp/platform/components/src/generic_modal/footer_content/footer_pagination.tsx @@ -0,0 +1,93 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import classNames from 'classnames'; +import React from 'react'; +import {useIntl} from 'react-intl'; + +import {ChevronLeftIcon, ChevronRightIcon} from '@mattermost/compass-icons/components'; + +import './footer_pagination.scss'; + +const BUTTON_ICON_SIZE = 16; + +type FooterPaginationProps = { + page: number; + total: number; + itemsPerPage: number; + onNextPage: (event: React.MouseEvent) => void; + onPreviousPage: (event: React.MouseEvent) => void; +}; + +export const FooterPagination = ({ + page, + total, + itemsPerPage, + onNextPage, + onPreviousPage, +}: FooterPaginationProps) => { + const {formatMessage} = useIntl(); + + const startCount = page * itemsPerPage; + const endCount = Math.min(startCount + itemsPerPage, total); + const totalPages = Math.trunc((total - 1) / itemsPerPage); + + const prevDisabled = page <= 0; + const nextDisabled = page >= totalPages; + + return ( +
+
+ {Boolean(total) && ( + formatMessage( + { + id: 'footer_pagination.count', + defaultMessage: 'Showing {startCount, number}-{endCount, number} of {total, number}', + }, + { + startCount: startCount + 1, + endCount, + total, + }, + ) + )} +
+
+ + +
+
+ ); +}; diff --git a/webapp/platform/components/src/generic_modal/footer_content/index.ts b/webapp/platform/components/src/generic_modal/footer_content/index.ts new file mode 100644 index 0000000000..6097345e39 --- /dev/null +++ b/webapp/platform/components/src/generic_modal/footer_content/index.ts @@ -0,0 +1,4 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +export * from './footer_pagination'; diff --git a/webapp/platform/components/src/generic_modal/generic_modal.tsx b/webapp/platform/components/src/generic_modal/generic_modal.tsx index 9f5ea7a357..68272eb8f4 100644 --- a/webapp/platform/components/src/generic_modal/generic_modal.tsx +++ b/webapp/platform/components/src/generic_modal/generic_modal.tsx @@ -34,13 +34,17 @@ export type Props = { enforceFocus?: boolean; container?: React.ReactNode | React.ReactNodeArray; ariaLabel?: string; - errorText?: string; + errorText?: string | React.ReactNode; compassDesign?: boolean; backdrop?: boolean; backdropClassName?: string; tabIndex?: number; children: React.ReactNode; keyboardEscape?: boolean; + headerInput?: React.ReactNode; + bodyPadding?: boolean; + footerContent?: React.ReactNode; + footerDivider?: boolean; }; type State = { @@ -56,6 +60,7 @@ export class GenericModal extends React.PureComponent { autoCloseOnConfirmButton: true, enforceFocus: true, keyboardEscape: true, + bodyPadding: true, }; constructor(props: Props) { @@ -195,7 +200,12 @@ export class GenericModal extends React.PureComponent { className='GenericModal__wrapper-enter-key-press-catcher' > - {this.props.compassDesign && headerText} + {this.props.compassDesign && ( + <> + {headerText} + {this.props.headerInput} + + )} {this.props.compassDesign ? ( @@ -208,14 +218,22 @@ export class GenericModal extends React.PureComponent { ) : ( headerText )} -
+
{this.props.children}
- {(cancelButton || confirmButton) && - {cancelButton} - {confirmButton} - } + {(cancelButton || confirmButton || this.props.footerContent) && ( + + {(cancelButton || confirmButton) ? ( + <> + {cancelButton} + {confirmButton} + + ) : ( + this.props.footerContent + )} + + )}
diff --git a/webapp/platform/components/src/index.tsx b/webapp/platform/components/src/index.tsx index f1615adf19..2ead4f1994 100644 --- a/webapp/platform/components/src/index.tsx +++ b/webapp/platform/components/src/index.tsx @@ -7,6 +7,7 @@ export type {CircleSkeletonLoaderProps, RectangleSkeletonLoaderProps} from './sk export type {Props as FocusTrapProps} from './focus_trap'; // components +export * from './generic_modal/footer_content'; export {GenericModal} from './generic_modal/generic_modal'; export {CircleSkeletonLoader, RectangleSkeletonLoader} from './skeleton_loader'; export * from './tour_tip'; From 8f9cde83b06679cd02f9e5d2d0e6e5c922c8ff70 Mon Sep 17 00:00:00 2001 From: Nathaniel Allred Date: Mon, 3 Apr 2023 12:12:27 -0500 Subject: [PATCH 14/58] MM-51763 Use STRIPE_PUBLIC_KEY from webpack (monorepo) (#22774) * use webpack build time stripe public key --- webapp/channels/src/components/payment_form/stripe.ts | 3 ++- webapp/channels/webpack.config.js | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/webapp/channels/src/components/payment_form/stripe.ts b/webapp/channels/src/components/payment_form/stripe.ts index 9599ad5936..3ba494b3db 100644 --- a/webapp/channels/src/components/payment_form/stripe.ts +++ b/webapp/channels/src/components/payment_form/stripe.ts @@ -25,4 +25,5 @@ function devConfirmCardSetup(confirmCardSetup: ConfirmCardSetupType): ConfirmCar export const getConfirmCardSetup = (isDevMode?: boolean) => (isDevMode ? devConfirmCardSetup : prodConfirmCardSetup); export const STRIPE_CSS_SRC = 'https://fonts.googleapis.com/css?family=Open+Sans:400,400i,600,600i&display=swap'; -export const STRIPE_PUBLIC_KEY = 'pk_test_ttEpW6dCHksKyfAFzh6MvgBj'; +//eslint-disable-next-line no-process-env +export const STRIPE_PUBLIC_KEY = process.env.STRIPE_PUBLIC_KEY || 'pk_test_ttEpW6dCHksKyfAFzh6MvgBj'; diff --git a/webapp/channels/webpack.config.js b/webapp/channels/webpack.config.js index 911550300f..2e7e3ab63c 100644 --- a/webapp/channels/webpack.config.js +++ b/webapp/channels/webpack.config.js @@ -441,7 +441,9 @@ if (DEV) { config.devtool = 'source-map'; } -const env = {}; +const env = { + STRIPE_PUBLIC_KEY: JSON.stringify(process.env.STRIPE_PUBLIC_KEY || ''), +}; if (DEV) { env.PUBLIC_PATH = JSON.stringify(publicPath); env.RUDDER_KEY = JSON.stringify(process.env.RUDDER_KEY || ''); From 1762dfce225420ec7b8058f1bdb92596ad23e50f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Mon, 3 Apr 2023 19:29:24 +0200 Subject: [PATCH 15/58] MM-51804 - add channels lhs not working (#22743) * MM-51804 - add channels lhs not working * open browse channels directly when user has no channel creation permissions (#22770) --- .../add_channels_cta_button.test.tsx.snap | 21 ++++++ .../sidebar/add_channels_cta_button.test.tsx | 73 +++++++++++++++++++ .../sidebar/add_channels_cta_button.tsx | 52 +++++++++---- .../__snapshots__/sidebar_list.test.tsx.snap | 1 + .../sidebar/sidebar_list/sidebar_list.tsx | 2 +- .../menu/menu_items/menu_cloud_trial.test.tsx | 1 - webapp/channels/src/sass/base/_structure.scss | 1 - .../src/sass/layout/_sidebar-left.scss | 24 +++--- 8 files changed, 147 insertions(+), 28 deletions(-) diff --git a/webapp/channels/src/components/sidebar/__snapshots__/add_channels_cta_button.test.tsx.snap b/webapp/channels/src/components/sidebar/__snapshots__/add_channels_cta_button.test.tsx.snap index 59e9f3bbdd..893aaa0ffe 100644 --- a/webapp/channels/src/components/sidebar/__snapshots__/add_channels_cta_button.test.tsx.snap +++ b/webapp/channels/src/components/sidebar/__snapshots__/add_channels_cta_button.test.tsx.snap @@ -11,6 +11,7 @@ exports[`components/new_channel_modal should match snapshot 1`] = ` aria-label="Add Channels Dropdown" className="SidebarChannelNavigator__addChannelsCtaLhsButton SidebarChannelNavigator__addChannelsCtaLhsButton--untouched" id="addChannelsCta" + onClick={[Function]} >
  • `; + +exports[`components/new_channel_modal should match snapshot when user has only join channel permissions 1`] = ` + +`; diff --git a/webapp/channels/src/components/sidebar/add_channels_cta_button.test.tsx b/webapp/channels/src/components/sidebar/add_channels_cta_button.test.tsx index 6066f4dcd3..68ab7ed614 100644 --- a/webapp/channels/src/components/sidebar/add_channels_cta_button.test.tsx +++ b/webapp/channels/src/components/sidebar/add_channels_cta_button.test.tsx @@ -80,6 +80,12 @@ describe('components/new_channel_modal', () => { system_user: { permissions: [Permissions.JOIN_PUBLIC_CHANNELS, Permissions.CREATE_PRIVATE_CHANNEL, Permissions.CREATE_PUBLIC_CHANNEL], }, + system_user_join_permissions: { + permissions: [Permissions.JOIN_PUBLIC_CHANNELS], + }, + system_user_create_public_permissions: { + permissions: [Permissions.JOIN_PUBLIC_CHANNELS, Permissions.CREATE_PUBLIC_CHANNEL], + }, }, }, }, @@ -99,6 +105,25 @@ describe('components/new_channel_modal', () => { ).toMatchSnapshot(); }); + test('should match snapshot when user has only join channel permissions', () => { + const userWithJoinChannelsPermission = { + currentUserId: 'current_user_id', + profiles: { + current_user_id: { + id: 'current_user_id', + roles: 'system_user_join_permissions', + }, + }, + } as unknown as UsersState; + mockState = {...mockState, entities: {...mockState.entities, users: userWithJoinChannelsPermission}}; + + expect( + shallow( + , + ), + ).toMatchSnapshot(); + }); + test('should find the add channels button when user has permissions', () => { const wrapper = mountWithIntl( , @@ -145,4 +170,52 @@ describe('components/new_channel_modal', () => { expect(trackEvent).toHaveBeenCalledWith('ui', 'add_channels_cta_button_clicked'); }); + + test('should not display as a Cta Dropdown when user only has permissions to join channels ', () => { + const userWithJoinChannelsPermission = { + currentUserId: 'current_user_id', + profiles: { + current_user_id: { + id: 'current_user_id', + roles: 'system_user_join_permissions', + }, + }, + } as unknown as UsersState; + mockState = {...mockState, entities: {...mockState.entities, users: userWithJoinChannelsPermission}}; + + const wrapper = mountWithIntl( + , + ); + + // do not find the menu + expect(wrapper.find('.AddChannelsCtaDropdown').exists()).toBeFalsy(); + + // only find the button + const button = wrapper.find('button#addChannelsCta'); + expect(button.exists()).toBeTruthy(); + + button.simulate('click'); + + // when clicked show the browse channels modal + expect(trackEvent).toHaveBeenCalledWith('ui', 'browse_channels_button_is_clicked'); + }); + + test('should still display as a Cta Dropdown when user has permissions to create at least one form of channel', () => { + const userWithJoinChannelsPermission = { + currentUserId: 'current_user_id', + profiles: { + current_user_id: { + id: 'current_user_id', + roles: 'system_user_create_public_permissions', + }, + }, + } as unknown as UsersState; + mockState = {...mockState, entities: {...mockState.entities, users: userWithJoinChannelsPermission}}; + + const wrapper = mountWithIntl( + , + ); + + expect(wrapper.find('.AddChannelsCtaDropdown').exists()).toBeTruthy(); + }); }); diff --git a/webapp/channels/src/components/sidebar/add_channels_cta_button.tsx b/webapp/channels/src/components/sidebar/add_channels_cta_button.tsx index 964bc81c4b..d3f1244edd 100644 --- a/webapp/channels/src/components/sidebar/add_channels_cta_button.tsx +++ b/webapp/channels/src/components/sidebar/add_channels_cta_button.tsx @@ -106,8 +106,28 @@ const AddChannelsCtaButton = (): JSX.Element | null => { ); }; - const trackOpen = (opened: boolean) => { - openAddChannelsCtaOpen(opened); + const addChannelsButton = (btnCallback?: () => void) => { + const handleClick = () => btnCallback?.(); + return ( + + ); + }; + + const storePreferencesAndTrackEvent = () => { trackEvent('ui', 'add_channels_cta_button_clicked'); if (!touchedAddChannelsCtaButton) { dispatch(savePreferences( @@ -122,26 +142,26 @@ const AddChannelsCtaButton = (): JSX.Element | null => { } }; + const trackOpen = (opened: boolean) => { + openAddChannelsCtaOpen(opened); + storePreferencesAndTrackEvent(); + }; + + if (!canCreateChannel) { + const browseChannelsAction = () => { + showMoreChannelsModal(); + storePreferencesAndTrackEvent(); + }; + return addChannelsButton(browseChannelsAction); + } + return ( - + {addChannelsButton()} { }; const store = mockStore(state); const wrapper = mountWithIntl(); - console.log(wrapper.debug()); expect(wrapper.find('.open-learn-more-trial-modal').exists()).toEqual(true); }); diff --git a/webapp/channels/src/sass/base/_structure.scss b/webapp/channels/src/sass/base/_structure.scss index 0ec379a86d..7171f80757 100644 --- a/webapp/channels/src/sass/base/_structure.scss +++ b/webapp/channels/src/sass/base/_structure.scss @@ -160,7 +160,6 @@ body.app__body #root { } #SidebarContainer.move--right { position: relative; - left: 65px; } } } diff --git a/webapp/channels/src/sass/layout/_sidebar-left.scss b/webapp/channels/src/sass/layout/_sidebar-left.scss index c670182893..9193927337 100644 --- a/webapp/channels/src/sass/layout/_sidebar-left.scss +++ b/webapp/channels/src/sass/layout/_sidebar-left.scss @@ -575,6 +575,19 @@ $sidebarOpacityAnimationDuration: 0.15s; } } + @media screen and (min-width: 768px) { + .SidebarNavContainer { + .scrollbar--view { + overflow: initial !important; + max-width: 240px; + } + } + + #SidebarContainer .SidebarChannelGroup .SidebarChannelGroupHeader { + max-width: 240px; + } + } + .SidebarCategory_newLabel { display: flex; width: 32px; @@ -741,6 +754,7 @@ $sidebarOpacityAnimationDuration: 0.15s; } .AddChannelsCtaDropdown .dropdown-menu { + min-width: 232px !important; margin-left: 20px; } @@ -748,20 +762,13 @@ $sidebarOpacityAnimationDuration: 0.15s; #addChannelsCta { display: flex; width: 100%; + margin-top: -6px; &:hover { background-color: var(--sidebar-text-hover-bg); } } - #AddChannelCtaDropdown { - position: fixed; - - ul { - min-width: 232px !important; - } - } - .SidebarChannelNavigator_inviteUsersSticky { position: absolute; z-index: 2; @@ -1021,7 +1028,6 @@ $sidebarOpacityAnimationDuration: 0.15s; /* Channels */ .SidebarChannel { display: flex; - overflow: hidden; height: 32px; /* height required for transition animation */ From dacac2e3ed0aea242d8963f3fa803ad0f0ca316c Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Mon, 3 Apr 2023 23:41:51 +0530 Subject: [PATCH 16/58] MM-51768: Scrub username/password from SQL datasource (#22731) https://mattermost.atlassian.net/browse/MM-51768 ```release-note NONE ``` --- server/channels/store/sqlstore/store.go | 4 +- server/channels/store/sqlstore/utils.go | 27 ++++++++++ server/channels/store/sqlstore/utils_test.go | 43 +++++++++++++++ server/config/database.go | 5 +- server/config/database_test.go | 6 +-- server/config/utils.go | 21 -------- server/config/utils_test.go | 55 -------------------- 7 files changed, 80 insertions(+), 81 deletions(-) diff --git a/server/channels/store/sqlstore/store.go b/server/channels/store/sqlstore/store.go index a1d7380b38..8000384e95 100644 --- a/server/channels/store/sqlstore/store.go +++ b/server/channels/store/sqlstore/store.go @@ -237,7 +237,9 @@ func SetupConnection(connType string, dataSource string, settings *model.SqlSett } for i := 0; i < DBPingAttempts; i++ { - mlog.Info("Pinging SQL", mlog.String("database", connType), mlog.String("dataSource", dataSource)) + // At this point, we have passed sql.Open, so we deliberately ignore any errors. + sanitized, _ := SanitizeDataSource(*settings.DriverName, dataSource) + mlog.Info("Pinging SQL", mlog.String("database", connType), mlog.String("dataSource", sanitized)) ctx, cancel := context.WithTimeout(context.Background(), DBPingTimeoutSecs*time.Second) defer cancel() err = db.PingContext(ctx) diff --git a/server/channels/store/sqlstore/utils.go b/server/channels/store/sqlstore/utils.go index 809439c820..5242f0c527 100644 --- a/server/channels/store/sqlstore/utils.go +++ b/server/channels/store/sqlstore/utils.go @@ -5,6 +5,7 @@ package sqlstore import ( "database/sql" + "errors" "io" "net/url" "strconv" @@ -206,3 +207,29 @@ func ResetReadTimeout(dataSource string) (string, error) { config.ReadTimeout = 0 return config.FormatDSN(), nil } + +func SanitizeDataSource(driverName, dataSource string) (string, error) { + switch driverName { + case model.DatabaseDriverPostgres: + u, err := url.Parse(dataSource) + if err != nil { + return "", err + } + u.User = url.UserPassword("****", "****") + params := u.Query() + params.Del("user") + params.Del("password") + u.RawQuery = params.Encode() + return u.String(), nil + case model.DatabaseDriverMysql: + cfg, err := mysql.ParseDSN(dataSource) + if err != nil { + return "", err + } + cfg.User = "****" + cfg.Passwd = "****" + return cfg.FormatDSN(), nil + default: + return "", errors.New("invalid drivername. Not postgres or mysql.") + } +} diff --git a/server/channels/store/sqlstore/utils_test.go b/server/channels/store/sqlstore/utils_test.go index 811ebf001a..96468323bb 100644 --- a/server/channels/store/sqlstore/utils_test.go +++ b/server/channels/store/sqlstore/utils_test.go @@ -6,6 +6,7 @@ package sqlstore import ( "testing" + "github.com/mattermost/mattermost-server/v6/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -160,3 +161,45 @@ func TestAppendMultipleStatementsFlag(t *testing.T) { }) } } + +func TestSanitizeDataSource(t *testing.T) { + t.Run(model.DatabaseDriverPostgres, func(t *testing.T) { + testCases := []struct { + Original string + Sanitized string + }{ + { + "postgres://mmuser:mostest@localhost/dummy?sslmode=disable", + "postgres://%2A%2A%2A%2A:%2A%2A%2A%2A@localhost/dummy?sslmode=disable", + }, + { + "postgres://localhost/dummy?sslmode=disable&user=mmuser&password=mostest", + "postgres://%2A%2A%2A%2A:%2A%2A%2A%2A@localhost/dummy?sslmode=disable", + }, + } + driver := model.DatabaseDriverPostgres + for _, tc := range testCases { + out, err := SanitizeDataSource(driver, tc.Original) + require.NoError(t, err) + assert.Equal(t, tc.Sanitized, out) + } + }) + + t.Run(model.DatabaseDriverMysql, func(t *testing.T) { + testCases := []struct { + Original string + Sanitized string + }{ + { + "mmuser:mostest@tcp(localhost:3306)/mattermost_test?charset=utf8mb4,utf8&readTimeout=30s&writeTimeout=30s", + "****:****@tcp(localhost:3306)/mattermost_test?readTimeout=30s&writeTimeout=30s&charset=utf8mb4%2Cutf8", + }, + } + driver := model.DatabaseDriverMysql + for _, tc := range testCases { + out, err := SanitizeDataSource(driver, tc.Original) + require.NoError(t, err) + assert.Equal(t, tc.Sanitized, out) + } + }) +} diff --git a/server/config/database.go b/server/config/database.go index f2463e33b4..dd508d9c4f 100644 --- a/server/config/database.go +++ b/server/config/database.go @@ -407,7 +407,10 @@ func (ds *DatabaseStore) RemoveFile(name string) error { // String returns the path to the database backing the config, masking the password. func (ds *DatabaseStore) String() string { - return stripPassword(ds.originalDsn, ds.driverName) + // This is called during the running of MM, so we expect the parsing of DSN + // to be successful. + sanitized, _ := sqlstore.SanitizeDataSource(ds.driverName, ds.originalDsn) + return sanitized } // Close cleans up resources associated with the store. diff --git a/server/config/database_test.go b/server/config/database_test.go index 4eab71fc5c..6954461a08 100644 --- a/server/config/database_test.go +++ b/server/config/database_test.go @@ -1107,12 +1107,12 @@ func TestDatabaseStoreString(t *testing.T) { if *mainHelper.GetSQLSettings().DriverName == "postgres" { maskedDSN := ds.String() assert.True(t, strings.HasPrefix(maskedDSN, "postgres://")) - assert.True(t, strings.Contains(maskedDSN, "mmuser")) + assert.False(t, strings.Contains(maskedDSN, "mmuser")) assert.False(t, strings.Contains(maskedDSN, "mostest")) } else { maskedDSN := ds.String() - assert.True(t, strings.HasPrefix(maskedDSN, "mysql://")) - assert.True(t, strings.Contains(maskedDSN, "mmuser")) + assert.False(t, strings.HasPrefix(maskedDSN, "mysql://")) + assert.False(t, strings.Contains(maskedDSN, "mmuser")) assert.False(t, strings.Contains(maskedDSN, "mostest")) } } diff --git a/server/config/utils.go b/server/config/utils.go index b343106562..f247ea4a43 100644 --- a/server/config/utils.go +++ b/server/config/utils.go @@ -179,27 +179,6 @@ func IsDatabaseDSN(dsn string) bool { strings.HasPrefix(dsn, "postgresql://") } -// stripPassword remove the password from a given DSN -func stripPassword(dsn, schema string) string { - prefix := schema + "://" - dsn = strings.TrimPrefix(dsn, prefix) - - i := strings.Index(dsn, ":") - j := strings.LastIndex(dsn, "@") - - // Return error if no @ sign is found - if j < 0 { - return "(omitted due to error parsing the DSN)" - } - - // Return back the input if no password is found - if i < 0 || i > j { - return prefix + dsn - } - - return prefix + dsn[:i+1] + dsn[j:] -} - func isJSONMap(data string) bool { var m map[string]any return json.Unmarshal([]byte(data), &m) == nil diff --git a/server/config/utils_test.go b/server/config/utils_test.go index e3b903eeb1..9c8de20d23 100644 --- a/server/config/utils_test.go +++ b/server/config/utils_test.go @@ -197,61 +197,6 @@ func TestIsDatabaseDSN(t *testing.T) { } } -func TestStripPassword(t *testing.T) { - for name, test := range map[string]struct { - DSN string - Schema string - ExpectedOut string - }{ - "mysql": { - DSN: "mysql://mmuser:password@tcp(localhost:3306)/mattermost?charset=utf8mb4,utf8&readTimeout=30s", - Schema: "mysql", - ExpectedOut: "mysql://mmuser:@tcp(localhost:3306)/mattermost?charset=utf8mb4,utf8&readTimeout=30s", - }, - "mysql idempotent": { - DSN: "mysql://mmuser:@tcp(localhost:3306)/mattermost?charset=utf8mb4,utf8&readTimeout=30s", - Schema: "mysql", - ExpectedOut: "mysql://mmuser:@tcp(localhost:3306)/mattermost?charset=utf8mb4,utf8&readTimeout=30s", - }, - "mysql: password with : and @": { - DSN: "mysql://mmuser:p:assw@ord@tcp(localhost:3306)/mattermost?charset=utf8mb4,utf8&readTimeout=30s", - Schema: "mysql", - ExpectedOut: "mysql://mmuser:@tcp(localhost:3306)/mattermost?charset=utf8mb4,utf8&readTimeout=30s", - }, - "mysql: password with @ and :": { - DSN: "mysql://mmuser:pa@sswo:rd@tcp(localhost:3306)/mattermost?charset=utf8mb4,utf8&readTimeout=30s", - Schema: "mysql", - ExpectedOut: "mysql://mmuser:@tcp(localhost:3306)/mattermost?charset=utf8mb4,utf8&readTimeout=30s", - }, - "postgres": { - DSN: "postgres://mmuser:password@localhost:5432/mattermost?sslmode=disable&connect_timeout=10", - Schema: "postgres", - ExpectedOut: "postgres://mmuser:@localhost:5432/mattermost?sslmode=disable&connect_timeout=10", - }, - "pipe": { - DSN: "mysql://user@unix(/path/to/socket)/dbname", - Schema: "mysql", - ExpectedOut: "mysql://user@unix(/path/to/socket)/dbname", - }, - "malformed without :": { - DSN: "postgres://mmuserpassword@localhost:5432/mattermost?sslmode=disable&connect_timeout=10", - Schema: "postgres", - ExpectedOut: "postgres://mmuserpassword@localhost:5432/mattermost?sslmode=disable&connect_timeout=10", - }, - "malformed without @": { - DSN: "postgres://mmuser:passwordlocalhost:5432/mattermost?sslmode=disable&connect_timeout=10", - Schema: "postgres", - ExpectedOut: "(omitted due to error parsing the DSN)", - }, - } { - t.Run(name, func(t *testing.T) { - out := stripPassword(test.DSN, test.Schema) - - assert.Equal(t, test.ExpectedOut, out) - }) - } -} - func TestIsJSONMap(t *testing.T) { tests := []struct { name string From af4c98cdf98eaefee1ecaa20e5d672dd03e6283f Mon Sep 17 00:00:00 2001 From: Ben Cooke Date: Mon, 3 Apr 2023 14:30:07 -0400 Subject: [PATCH 17/58] [MM-51724] (#22740) * createUserAccessToken updates * lint --- server/channels/api4/user.go | 13 ++++++++++-- server/channels/api4/user_test.go | 33 ++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/server/channels/api4/user.go b/server/channels/api4/user.go index ba2ab6e336..11d4a71e0f 100644 --- a/server/channels/api4/user.go +++ b/server/channels/api4/user.go @@ -2372,10 +2372,14 @@ func createUserAccessToken(c *Context, w http.ResponseWriter, r *http.Request) { audit.AddEventParameter(auditRec, "user_id", c.Params.UserId) defer c.LogAuditRec(auditRec) - if user, err := c.App.GetUser(c.Params.UserId); err == nil { - audit.AddEventParameterAuditable(auditRec, "user", user) + user, err := c.App.GetUser(c.Params.UserId) + if err != nil { + c.Err = err + return } + audit.AddEventParameterAuditable(auditRec, "user", user) + if c.AppContext.Session().IsOAuth { c.SetPermissionError(model.PermissionCreateUserAccessToken) c.Err.DetailedError += ", attempted access by oauth app" @@ -2405,6 +2409,11 @@ func createUserAccessToken(c *Context, w http.ResponseWriter, r *http.Request) { return } + if user.IsSystemAdmin() && !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) { + c.SetPermissionError(model.PermissionManageSystem) + return + } + accessToken.UserId = c.Params.UserId accessToken.Token = "" diff --git a/server/channels/api4/user_test.go b/server/channels/api4/user_test.go index 893d7f6aca..b6dde5e2a1 100644 --- a/server/channels/api4/user_test.go +++ b/server/channels/api4/user_test.go @@ -4339,7 +4339,38 @@ func TestCreateUserAccessToken(t *testing.T) { CheckForbiddenStatus(t, resp) }) - t.Run("create user access token for basic user as as system admin", func(t *testing.T) { + t.Run("create user access token for another user, with permission", func(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + + th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true }) + th.AddPermissionToRole(model.PermissionEditOtherUsers.Id, model.SystemUserManagerRoleId) + th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserManagerRoleId+" "+model.SystemUserAccessTokenRoleId, false) + + rtoken, _, err := th.Client.CreateUserAccessToken(th.BasicUser2.Id, "test token") + require.NoError(t, err) + assert.Equal(t, th.BasicUser2.Id, rtoken.UserId) + + oldSessionToken := th.Client.AuthToken + defer func() { th.Client.AuthToken = oldSessionToken }() + + assertToken(t, th, rtoken, th.BasicUser2.Id) + }) + + t.Run("create user access token for system admin, as system user manager", func(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + + th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true }) + th.AddPermissionToRole(model.PermissionEditOtherUsers.Id, model.SystemUserManagerRoleId) + th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserManagerRoleId+" "+model.SystemUserAccessTokenRoleId, false) + + _, resp, err := th.Client.CreateUserAccessToken(th.SystemAdminUser.Id, "test token") + require.Error(t, err) + CheckForbiddenStatus(t, resp) + }) + + t.Run("create user access token for basic user as a system admin", func(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() From 3f6452bdf548174f9efb7db651c93c575357768e Mon Sep 17 00:00:00 2001 From: M-ZubairAhmed Date: Tue, 4 Apr 2023 00:59:04 +0530 Subject: [PATCH 18/58] init (#22752) --- webapp/channels/.eslintignore | 1 - webapp/channels/.eslintrc.json | 16 +---------- webapp/channels/.gobom.json | 1 - webapp/channels/Makefile | 52 ---------------------------------- webapp/channels/jest.config.js | 3 +- webapp/channels/package.json | 1 - webapp/channels/tsconfig.json | 2 -- webapp/package-lock.json | 23 --------------- 8 files changed, 2 insertions(+), 97 deletions(-) diff --git a/webapp/channels/.eslintignore b/webapp/channels/.eslintignore index 9c3001349d..468bb89127 100644 --- a/webapp/channels/.eslintignore +++ b/webapp/channels/.eslintignore @@ -1,4 +1,3 @@ -e2e/results node_modules dist lib diff --git a/webapp/channels/.eslintrc.json b/webapp/channels/.eslintrc.json index 048bb4b85e..7a3865a6db 100644 --- a/webapp/channels/.eslintrc.json +++ b/webapp/channels/.eslintrc.json @@ -2,22 +2,19 @@ "root": true, "extends": [ "plugin:mattermost/react", - "plugin:cypress/recommended", "plugin:react-hooks/recommended" ], "plugins": [ "@babel/eslint-plugin", "mattermost", "import", - "cypress", "no-only-tests", "@typescript-eslint", "formatjs" ], "parser": "@typescript-eslint/parser", "env": { - "jest": true, - "cypress/globals": true + "jest": true }, "settings": { "import/resolver": "webpack", @@ -166,17 +163,6 @@ "no-process-env": 0, "prefer-arrow-callback": 0 } - }, - { - "files": ["e2e/**"], - "rules": { - "@babel/no-unused-expressions": 0, - "func-names": 0, - "import/no-unresolved": 0, - "max-nested-callbacks": 0, - "no-process-env": 0, - "no-unused-expressions": 0 - } } ] } diff --git a/webapp/channels/.gobom.json b/webapp/channels/.gobom.json index 3279174525..4ec47b22c6 100644 --- a/webapp/channels/.gobom.json +++ b/webapp/channels/.gobom.json @@ -3,7 +3,6 @@ "properties": { "GomodMainOnly": true, "GomodExcludes": "_tests/|[-_]generators?$|^plugin/checker$", - "NpmExcludes": "/e2e$", "GradlePath": "./gradlew:../gradlew" }, "filters": [ diff --git a/webapp/channels/Makefile b/webapp/channels/Makefile index 889907e624..aa20ad2ca2 100644 --- a/webapp/channels/Makefile +++ b/webapp/channels/Makefile @@ -6,58 +6,6 @@ export NODE_OPTIONS=--max-old-space-size=4096 i18n-extract: ## Extract strings for translation from the source code npm run i18n-extract -e2e/playwright/node_modules: - @echo Install Playwright and its dependencies - cd e2e/playwright && npm install - -.PHONY: e2e-test -e2e-test: - @echo E2E: Running mattermost-mysql-e2e - @if [ $(shell docker ps -a | grep -ci mattermost-mysql-e2e) -eq 0 ]; then \ - echo starting mattermost-mysql-e2e; \ - docker run --name mattermost-mysql-e2e -p 35476:3306 -e MYSQL_ROOT_PASSWORD=mostest \ - -e MYSQL_USER=mmuser -e MYSQL_PASSWORD=mostest -e MYSQL_DATABASE=mattermost_test -d mysql:5.7 > /dev/null; \ - elif [ $(shell docker ps | grep -ci mattermost-mysql-e2e) -eq 0 ]; then \ - echo restarting mattermost-mysql-e2e; \ - docker start mattermost-mysql-e2e > /dev/null; \ - fi - - cd $(BUILD_SERVER_DIR) && [[ -f config/config.json ]] && \ - cp config/config.json config/config-backup.json && make config-reset || \ - echo "config.json not found" && make config-reset - - @echo E2E: Starting the server - cd $(BUILD_SERVER_DIR) && $(MAKE) run - - @echo E2E: Generating test data - cd $(BUILD_SERVER_DIR) && $(MAKE) test-data - - @echo E2E: Running end-to-end testing - cd e2e && npm install && npm run cypress:run - - @echo E2E: Stoppping the server - cd $(BUILD_SERVER_DIR) && $(MAKE) stop - - @echo E2E: stopping mattermost-mysql-e2e - docker stop mattermost-mysql-e2e > /dev/null - - cd $(BUILD_SERVER_DIR) && [[ -f config/config-backup.json ]] && \ - cp config/config-backup.json config/config.json && echo "revert local config.json" || \ - echo "config-backup.json not found" && sed -i'' -e 's|"DataSource": ".*"|"DataSource": "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8\u0026readTimeout=30s\u0026writeTimeout=30s"|g' config/config.json - - @echo E2E: Tests completed - -.PHONY: clean-e2e -clean-e2e: - @if [ $(shell docker ps -a | grep -ci mattermost-mysql-e2e) -eq 1 ]; then \ - echo stopping mattermost-mysql-e2e; \ - docker stop mattermost-mysql-e2e > /dev/null; \ - fi - - cd $(BUILD_SERVER_DIR) && [[ -f config/config-backup.json ]] && \ - cp config/config-backup.json config/config.json && echo "revert local config.json" || \ - echo "config-backup.json not found" && sed -i'' -e 's|"DataSource": ".*"|"DataSource": "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8\u0026readTimeout=30s\u0026writeTimeout=30s"|g' config/config.json - .PHONY: emojis emojis: ## Creates emoji JSON, JSX and Go files and extracts emoji images from the system font SERVER_DIR=$(BUILD_SERVER_DIR) npm run make-emojis diff --git a/webapp/channels/jest.config.js b/webapp/channels/jest.config.js index 123f6d7e57..01d80ffe8d 100644 --- a/webapp/channels/jest.config.js +++ b/webapp/channels/jest.config.js @@ -5,7 +5,7 @@ const config = { snapshotSerializers: ['enzyme-to-json/serializer'], - testPathIgnorePatterns: ['/node_modules/', '/e2e/'], + testPathIgnorePatterns: ['/node_modules/'], clearMocks: true, collectCoverageFrom: [ 'actions/src/**/*.{js,jsx,ts,tsx}', @@ -17,7 +17,6 @@ const config = { 'selectors/src/**/*.{js,jsx,ts,tsx}', 'stores/src/**/*.{js,jsx,ts,tsx}', 'utils/src/**/*.{js,jsx,ts,tsx}', - '!e2e/**', ], coverageReporters: ['lcov', 'text-summary'], moduleNameMapper: { diff --git a/webapp/channels/package.json b/webapp/channels/package.json index 7f33c6b05f..830cbfae08 100644 --- a/webapp/channels/package.json +++ b/webapp/channels/package.json @@ -169,7 +169,6 @@ "enzyme-to-json": "3.6.2", "eslint": "7.32.0", "eslint-import-resolver-webpack": "0.13.2", - "eslint-plugin-cypress": "2.11.3", "eslint-plugin-formatjs": "4.3.4", "eslint-plugin-header": "3.1.1", "eslint-plugin-import": "2.23.4", diff --git a/webapp/channels/tsconfig.json b/webapp/channels/tsconfig.json index f71364fdc0..85f5958590 100644 --- a/webapp/channels/tsconfig.json +++ b/webapp/channels/tsconfig.json @@ -28,8 +28,6 @@ "reselect": ["packages/reselect/src"], "@mui/styled-engine": ["./node_modules/@mui/styled-engine-sc"], "!!file-loader*": ["utils/empty-string"], - "@e2e-support/*": ["e2e/playwright/support/*"], - "@e2e-test.config": ["e2e/playwright/test.config.ts"] } }, "include": [ diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 923fdfd0e4..987b8de866 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -3905,7 +3905,6 @@ "enzyme-to-json": "3.6.2", "eslint": "7.32.0", "eslint-import-resolver-webpack": "0.13.2", - "eslint-plugin-cypress": "2.11.3", "eslint-plugin-formatjs": "4.3.4", "eslint-plugin-header": "3.1.1", "eslint-plugin-import": "2.23.4", @@ -17819,18 +17818,6 @@ "eslint": ">=4.0.0" } }, - "node_modules/eslint-plugin-cypress": { - "version": "2.11.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.3.tgz", - "integrity": "sha512-hOoAid+XNFtpvOzZSNWP5LDrQBEJwbZwjib4XJ1KcRYKjeVj0mAmPmucG4Egli4j/aruv+Ow/acacoloWWCl9Q==", - "dev": true, - "dependencies": { - "globals": "^11.12.0" - }, - "peerDependencies": { - "eslint": ">= 3.2.1" - } - }, "node_modules/eslint-plugin-formatjs": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/eslint-plugin-formatjs/-/eslint-plugin-formatjs-4.3.4.tgz", @@ -50096,15 +50083,6 @@ "eslint-rule-composer": "^0.3.0" } }, - "eslint-plugin-cypress": { - "version": "2.11.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.3.tgz", - "integrity": "sha512-hOoAid+XNFtpvOzZSNWP5LDrQBEJwbZwjib4XJ1KcRYKjeVj0mAmPmucG4Egli4j/aruv+Ow/acacoloWWCl9Q==", - "dev": true, - "requires": { - "globals": "^11.12.0" - } - }, "eslint-plugin-formatjs": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/eslint-plugin-formatjs/-/eslint-plugin-formatjs-4.3.4.tgz", @@ -55129,7 +55107,6 @@ "enzyme-to-json": "3.6.2", "eslint": "7.32.0", "eslint-import-resolver-webpack": "0.13.2", - "eslint-plugin-cypress": "2.11.3", "eslint-plugin-formatjs": "4.3.4", "eslint-plugin-header": "3.1.1", "eslint-plugin-import": "2.23.4", From f97a11680b3df8434331f550cad0035ec571a54e Mon Sep 17 00:00:00 2001 From: LeonardJouve <81326532+LeonardJouve@users.noreply.github.com> Date: Mon, 3 Apr 2023 22:04:18 +0200 Subject: [PATCH 19/58] Fix add bot error handling (#22649) Co-authored-by: Mattermost Build --- .../src/components/integrations/bots/add_bot/add_bot.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webapp/channels/src/components/integrations/bots/add_bot/add_bot.tsx b/webapp/channels/src/components/integrations/bots/add_bot/add_bot.tsx index 55bb0b9126..5dae1cbf73 100644 --- a/webapp/channels/src/components/integrations/bots/add_bot/add_bot.tsx +++ b/webapp/channels/src/components/integrations/bots/add_bot/add_bot.tsx @@ -249,6 +249,7 @@ export default class AddBot extends React.PureComponent { /> ), }); + return; } else if (this.state.pictureFile.size > this.props.maxFileSize) { this.setState({ error: ( @@ -258,6 +259,7 @@ export default class AddBot extends React.PureComponent { /> ), }); + return; } } From 8d301c0d64d5574632644b4b411edd29c5c2ed14 Mon Sep 17 00:00:00 2001 From: Saturnino Abril Date: Tue, 4 Apr 2023 06:04:11 +0800 Subject: [PATCH 20/58] fix: /test url and json (#22780) --- server/channels/app/slashcommands/command_loadtest.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/channels/app/slashcommands/command_loadtest.go b/server/channels/app/slashcommands/command_loadtest.go index cd7ab9f217..a0b02267b4 100644 --- a/server/channels/app/slashcommands/command_loadtest.go +++ b/server/channels/app/slashcommands/command_loadtest.go @@ -629,7 +629,7 @@ func (*LoadTestProvider) URLCommand(a *app.App, c request.CTX, args *model.Comma // provide a shortcut to easily access tests stored in doc/developer/tests if !strings.HasPrefix(url, "http") { - url = "https://raw.githubusercontent.com/mattermost/mattermost-server/master/tests/" + url + url = "https://raw.githubusercontent.com/mattermost/mattermost-server/master/server/tests/" + url if path.Ext(url) == "" { url += ".md" @@ -683,7 +683,7 @@ func (*LoadTestProvider) JsonCommand(a *app.App, c request.CTX, args *model.Comm // provide a shortcut to easily access tests stored in doc/developer/tests if !strings.HasPrefix(url, "http") { - url = "https://raw.githubusercontent.com/mattermost/mattermost-server/master/tests/" + url + url = "https://raw.githubusercontent.com/mattermost/mattermost-server/master/server/tests/" + url if path.Ext(url) == "" { url += ".json" From f1f54508f414275226409691aa8a690889a723cb Mon Sep 17 00:00:00 2001 From: Furqan Malik Date: Mon, 3 Apr 2023 18:22:48 -0400 Subject: [PATCH 21/58] Fixed Add Channel_test_cases (#22768) * Fixed Add Channel_test_cases * fixed more test cases * fixed lint --- .../accessibility/accessibility_sidebar_spec.ts | 2 +- .../channel_sidebar/category_sorting_1_spec.ts | 2 +- .../channels/channel_sidebar/category_sorting_spec.ts | 2 +- .../channels/channel_sidebar/custom_categories_spec.ts | 2 +- .../channel_sidebar/new_channel_dropdown_spec.ts | 2 +- .../channels/emoji/recently_used_emoji_1_spec.ts | 10 ++++++++-- .../accessibility/accessibility_input_fields_spec.js | 2 +- .../channels/enterprise/ldap/ldap_guest_spec.js | 4 ++-- .../system_scheme_permission_part2_spec.js | 6 +++--- .../integration/channels/mark_as_unread/helpers.js | 1 + e2e-tests/cypress/tests/support/ui/sidebar_left.ts | 4 ++-- 11 files changed, 22 insertions(+), 15 deletions(-) diff --git a/e2e-tests/cypress/tests/integration/channels/accessibility/accessibility_sidebar_spec.ts b/e2e-tests/cypress/tests/integration/channels/accessibility/accessibility_sidebar_spec.ts index 9c67b1250b..232f62acdf 100644 --- a/e2e-tests/cypress/tests/integration/channels/accessibility/accessibility_sidebar_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/accessibility/accessibility_sidebar_spec.ts @@ -69,7 +69,7 @@ describe('Verify Accessibility Support in Channel Sidebar Navigation', () => { cy.uiGetLHSAddChannelButton().focus().tab().tab({shift: true}); // * Verify if the Plus button has focus - cy.findByRole('button', {name: 'Add Channel Dropdown'}).should('be.focused'); + cy.uiGetLHSAddChannelButton().should('be.focused'); cy.focused().tab(); // * Verify if the Plus button has focus diff --git a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_1_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_1_spec.ts index bf2f6e9011..f7b71b4115 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_1_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_1_spec.ts @@ -140,7 +140,7 @@ function createCategoryFromSidebarMenu() { const categoryName = `category-${getRandomId()}`; // # Click on the sidebar menu dropdown - cy.findByLabelText('Add Channel Dropdown').click(); + cy.uiGetLHSAddChannelButton().click(); // # Click on create category link cy.findByText('Create New Category').should('be.visible').click(); diff --git a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_spec.ts index 69086ce680..82e3b4a086 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_spec.ts @@ -23,7 +23,7 @@ describe('Category sorting', () => { it('MM-T3916 Create Category character limit', () => { // # Click on the sidebar menu dropdown - cy.findByLabelText('Add Channel Dropdown').click(); + cy.uiGetLHSAddChannelButton().click(); // # Click on create category link cy.findByText('Create New Category').should('be.visible').click(); diff --git a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/custom_categories_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/custom_categories_spec.ts index 30918ebbb3..4822d10432 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/custom_categories_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/custom_categories_spec.ts @@ -90,7 +90,7 @@ function createCategoryFromSidebarMenu() { const categoryName = `category-${getRandomId()}`; // # Click on the sidebar menu dropdown - cy.findByLabelText('Add Channel Dropdown').click(); + cy.uiGetLHSAddChannelButton().click(); // # Click on create category link cy.findByText('Create New Category').should('be.visible').click(); diff --git a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/new_channel_dropdown_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/new_channel_dropdown_spec.ts index 17114e21aa..4aad6c337a 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/new_channel_dropdown_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/new_channel_dropdown_spec.ts @@ -62,7 +62,7 @@ describe('Channel sidebar', () => { cy.url().should('include', `/${teamName}/channels/town-square`); // # Click the New Channel Dropdown button - cy.get('.AddChannelDropdown_dropdownButton').should('be.visible').click(); + cy.uiGetLHSAddChannelButton().should('be.visible').click(); // # Click the Browse Channels dropdown item cy.get('.AddChannelDropdown .MenuItem:contains(Browse Channels) button').should('be.visible').click(); diff --git a/e2e-tests/cypress/tests/integration/channels/emoji/recently_used_emoji_1_spec.ts b/e2e-tests/cypress/tests/integration/channels/emoji/recently_used_emoji_1_spec.ts index 0d016ea33d..fcaeb3b38b 100644 --- a/e2e-tests/cypress/tests/integration/channels/emoji/recently_used_emoji_1_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/emoji/recently_used_emoji_1_spec.ts @@ -105,7 +105,10 @@ describe('Recent Emoji', () => { cy.uiGetPostTextBox().type('{enter} {enter}').wait(TIMEOUTS.TWO_SEC); // # Hover over the last post by opening dot menu on it - cy.clickPostDotMenu(); + cy.getLastPostId().then((postId) => { + // # Click on post dot menu so we can check for reaction icon + cy.get(`#post_${postId}`).trigger('mouseover'); + }); cy.get('#recent_reaction_0').should('exist').then((recentReaction) => { // * Assert that custom emoji is present as most recent in quick reaction menu @@ -152,7 +155,10 @@ describe('Recent Emoji', () => { cy.reload(); // # Hover over the last post by opening dot menu on it - cy.clickPostDotMenu(); + cy.getLastPostId().then((postId) => { + // # Click on post dot menu so we can check for reaction icon + cy.get(`#post_${postId}`).trigger('mouseover'); + }); cy.get('#recent_reaction_0').should('exist').then((recentReaction) => { // * Assert that instead of custom emoji the system emoji is present as most recent in quick reaction menu diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/accessibility/accessibility_input_fields_spec.js b/e2e-tests/cypress/tests/integration/channels/enterprise/accessibility/accessibility_input_fields_spec.js index 8626033949..08f25fc8d4 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/accessibility/accessibility_input_fields_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/accessibility/accessibility_input_fields_spec.js @@ -196,7 +196,7 @@ describe('Verify Accessibility Support in different input fields', () => { cy.get('#FormattingControl_ul').should('be.focused').and('have.attr', 'aria-label', 'bulleted list').tab(); // * Verify if the focus is on the numbered list button - cy.get('#FormattingControl_ol').should('be.focused').and('have.attr', 'aria-label', 'numbered list').tab(); + cy.get('#FormattingControl_ol').should('be.focused').and('have.attr', 'aria-label', 'numbered list').tab().tab(); // * Verify if the focus is on the formatting options button cy.get('#toggleFormattingBarButton').should('be.focused').and('have.attr', 'aria-label', 'formatting').tab(); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_guest_spec.js b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_guest_spec.js index fda7dca517..79dbf33ab8 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_guest_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_guest_spec.js @@ -159,7 +159,7 @@ describe('LDAP guest', () => { // # Create team if no membership cy.skipOrCreateTeam(testSettings, getRandomId()).then(() => { // * Verify user is a member - cy.findByRole('button', {name: 'Add Channel Dropdown'}).should('exist'); + cy.uiGetLHSAddChannelButton().should('exist'); // # Demote the user demoteUserToGuest(user2Data); @@ -173,7 +173,7 @@ describe('LDAP guest', () => { cy.uiAddDirectMessage().should('exist'); // * Check the user is a guest - cy.findByRole('button', {name: 'Add Channel Dropdown'}).should('not.exist'); + cy.uiGetLHSAddChannelButton().should('not.exist'); }); }); }); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/system_scheme_permission_part2_spec.js b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/system_scheme_permission_part2_spec.js index 53e063aef9..33ae5b8c77 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/system_scheme_permission_part2_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/system_scheme_permission_part2_spec.js @@ -53,7 +53,7 @@ describe('System Scheme', () => { cy.findByTestId('systemScheme-link').should('be.visible').click().wait(TIMEOUTS.HALF_SEC); // # Click on `Reset to defaults` - cy.findByTestId('resetPermissionsToDefault').should('be.visible').click().wait(TIMEOUTS.HALF_SEC); + cy.findByTestId('resetPermissionsToDefault').scrollIntoView().should('be.visible').click().wait(TIMEOUTS.HALF_SEC); // # Confirm the dialog cy.get('#confirmModalButton').click().wait(TIMEOUTS.TWO_SEC); @@ -78,10 +78,10 @@ describe('System Scheme', () => { cy.findByTestId('all_users-private_channel-create_private_channel-checkbox').should('not.have.class', 'checked'); // # Click on `Reset to defaults` - cy.findByTestId('resetPermissionsToDefault').should('be.visible').click().wait(TIMEOUTS.HALF_SEC); + cy.findByTestId('resetPermissionsToDefault').scrollIntoView().should('be.visible').click().wait(TIMEOUTS.HALF_SEC); // # Confirm the dialog - cy.get('#confirmModalButton').click().wait(TIMEOUTS.HALF_SEC); + cy.get('#confirmModalButton').scrollIntoView().click().wait(TIMEOUTS.HALF_SEC); // # Save changes cy.get('#saveSetting').click().wait(TIMEOUTS.TWO_SEC); diff --git a/e2e-tests/cypress/tests/integration/channels/mark_as_unread/helpers.js b/e2e-tests/cypress/tests/integration/channels/mark_as_unread/helpers.js index 4482bcb782..fbcbea8f4b 100644 --- a/e2e-tests/cypress/tests/integration/channels/mark_as_unread/helpers.js +++ b/e2e-tests/cypress/tests/integration/channels/mark_as_unread/helpers.js @@ -21,6 +21,7 @@ export function markAsUnreadShouldBeAbsent(postId, prefix = 'post', location = ' within(() => { cy.findByText('Mark as Unread').should('not.exist'); }); + cy.get('body').type('esc'); } export function switchToChannel(channel) { diff --git a/e2e-tests/cypress/tests/support/ui/sidebar_left.ts b/e2e-tests/cypress/tests/support/ui/sidebar_left.ts index 1168b705dd..58ae372f82 100644 --- a/e2e-tests/cypress/tests/support/ui/sidebar_left.ts +++ b/e2e-tests/cypress/tests/support/ui/sidebar_left.ts @@ -32,7 +32,7 @@ Cypress.Commands.add('uiOpenTeamMenu', (item = '') => { Cypress.Commands.add('uiGetLHSAddChannelButton', () => { return cy.uiGetLHS(). - findByRole('button', {name: 'Add Channel Dropdown'}); + find('.AddChannelDropdown_dropdownButton'); }); Cypress.Commands.add('uiGetLHSTeamMenu', () => { @@ -89,7 +89,7 @@ Cypress.Commands.add('uiGetLhsSection', (section) => { }); Cypress.Commands.add('uiBrowseOrCreateChannel', (item) => { - cy.findByRole('button', {name: 'Add Channel Dropdown'}). + cy.get('.AddChannelDropdown_dropdownButton'). should('be.visible'). click(); cy.get('.dropdown-menu').should('be.visible'); From e04512a51a79acd2d8c068b3b2872c22886c2e98 Mon Sep 17 00:00:00 2001 From: Konstantin Date: Tue, 4 Apr 2023 09:37:15 +0200 Subject: [PATCH 22/58] Translated using Weblate (Russian) Currently translated at 99.8% (5751 of 5759 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ru/ --- webapp/channels/src/i18n/ru.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/webapp/channels/src/i18n/ru.json b/webapp/channels/src/i18n/ru.json index bfca5442bf..51ff0ffb9c 100644 --- a/webapp/channels/src/i18n/ru.json +++ b/webapp/channels/src/i18n/ru.json @@ -2127,7 +2127,7 @@ "admin.service.corsExposedHeadersTitle": "CORS открытые заголовки:", "admin.service.corsHeadersEx": "X-Мой-Заголовок", "admin.service.corsTitle": "Разрешить кроссдоменные запросы от:", - "admin.service.developerDesc": "При значении \"да\" на красной панели сверху будут показываться ошибки JavaScript. Не рекомендуется использовать на \"боевом\" сервере. ", + "admin.service.developerDesc": "При значении \"да\" на красной панели сверху будут показываться ошибки JavaScript. Не рекомендуется использовать на \"боевом\" сервере.", "admin.service.developerTitle": "Включить режим разработчика: ", "admin.service.disableBotOwnerDeactivatedTitle": "Отключить учетные записи ботов когда их владелец деактивирован:", "admin.service.disableBotWhenOwnerIsDeactivated": "Когда пользователь деактивирован, отключаются все учетные записи ботов, управляемых этим пользователем.Чтобы обратно включить учетные записи ботов, перейдите в [Интеграции > Учетные записи ботов]({siteURL}/_redirect/integrations/bots).", @@ -4156,9 +4156,14 @@ "modal.manual_status.title_offline": "Ваш статус установлен на \"Не в сети\"", "modal.manual_status.title_ooo": "Ваш статус установлен на \"Не на работе\"", "more.details": "Подробнее", + "more_channels.channel_purpose": "Информация о канале: Индикатор членства: Присоединились, Количество участников {memberCount}, Цель: {channelPurpose}", + "more_channels.count": "{count} Результатов", + "more_channels.count_one": "1 Результат", + "more_channels.count_zero": "Нет результатов", "more_channels.create": "Создать канал", + "more_channels.hide_joined": "Скрыть присоединенные", "more_channels.next": "Далее", - "more_channels.noMore": "Доступных каналов не найдено", + "more_channels.noMore": "Нет результатов поиска для \"{text}\"", "more_channels.prev": "Предыдущая", "more_channels.show_archived_channels": "Показать: Архивированные каналы", "more_channels.show_public_channels": "Показать: Публичные каналы", From 114d76176e896edc50d39cb1f1d991ae9c2a57c6 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 4 Apr 2023 09:37:17 +0200 Subject: [PATCH 23/58] Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/ --- server/i18n/de.json | 52 ----------------------------- server/i18n/en_AU.json | 52 ----------------------------- server/i18n/es.json | 52 ----------------------------- server/i18n/fr.json | 48 -------------------------- server/i18n/hu.json | 48 -------------------------- server/i18n/it.json | 48 -------------------------- server/i18n/ja.json | 52 ----------------------------- server/i18n/ko.json | 12 ------- server/i18n/nl.json | 52 ----------------------------- server/i18n/pl.json | 52 ----------------------------- server/i18n/pt-BR.json | 12 ------- server/i18n/ru.json | 52 ----------------------------- server/i18n/sv.json | 52 ----------------------------- server/i18n/tr.json | 52 ----------------------------- server/i18n/uk.json | 12 ------- server/i18n/zh-CN.json | 52 ----------------------------- server/i18n/zh-TW.json | 4 --- webapp/channels/src/i18n/bg.json | 1 - webapp/channels/src/i18n/de.json | 11 ------ webapp/channels/src/i18n/en_AU.json | 1 - webapp/channels/src/i18n/es.json | 1 - webapp/channels/src/i18n/fa.json | 1 - webapp/channels/src/i18n/fr.json | 1 - webapp/channels/src/i18n/hu.json | 1 - webapp/channels/src/i18n/it.json | 1 - webapp/channels/src/i18n/ja.json | 13 -------- webapp/channels/src/i18n/ko.json | 1 - webapp/channels/src/i18n/nl.json | 1 - webapp/channels/src/i18n/pl.json | 11 ------ webapp/channels/src/i18n/pt-BR.json | 1 - webapp/channels/src/i18n/ro.json | 1 - webapp/channels/src/i18n/ru.json | 6 ---- webapp/channels/src/i18n/sv.json | 1 - webapp/channels/src/i18n/tr.json | 1 - webapp/channels/src/i18n/uk.json | 1 - webapp/channels/src/i18n/zh-CN.json | 1 - webapp/channels/src/i18n/zh-TW.json | 1 - 37 files changed, 761 deletions(-) diff --git a/server/i18n/de.json b/server/i18n/de.json index f5d555cb6e..8960847caf 100644 --- a/server/i18n/de.json +++ b/server/i18n/de.json @@ -9022,50 +9022,6 @@ "id": "api.custom_groups.count_err", "translation": "Fehler beim Zählen der Gruppen" }, - { - "id": "api.templates.server_inactivity_title", - "translation": "Erhöhe die Produktivität mit diesen tollen Funktionen" - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "Hi {{.Name}}, wir haben bemerkt, dass Dein Mattermost Server etwas Staub ansetzt, Schau mal auf die neuen Funktionen, die Dir helfen die Belastung Deines Team zu senken." - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "Öffne Mattermost um Dein Team produktiver zu machen!" - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "Verwalte Aufgaben mit " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "Arbeitsablauf-Verwaltung mit " - }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "Gastzugriff auf angegebene " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "Komm und teste es!" - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "Öffne Mattermost" - }, - { - "id": "Playbooks", - "translation": "Playbooks" - }, - { - "id": "Channels", - "translation": "Kanäle" - }, - { - "id": "Boards", - "translation": "Boards" - }, { "id": "app.job.get_all_jobs_by_type_and_status.app_error", "translation": "Kann nicht alle Jobs nach Typ und Status holen." @@ -9170,10 +9126,6 @@ "id": "api.elasticsearch.test_elasticsearch_settings_nil.app_error", "translation": "Die Elasticsearch-Einstellungen haben nicht definierte Werte." }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "Du hast diese einmalige E-Mail erhalten, weil dein Mattermost-Server für mehr als {{.Hours}} Stunden inaktiv war. Diese E-Mail wurde automatisch von deinem Mattermost-Server generiert." - }, { "id": "api.file.cloud_upload.app_error", "translation": "Hochladen über mmctl zu einer Cloud Instanz wird nicht unterstützt. Bitte prüfe die Dokumentation: https://docs.mattermost.com/manage/cloud-data-export.html." @@ -9510,10 +9462,6 @@ "id": "model.group.name.reserved_name.app_error", "translation": "Gruppenname existiert bereits als reservierter Name" }, - { - "id": "app.plugin.product_mode.app_error", - "translation": "Plugin {{.Name}} kann im Produktmodus nicht aktiviert werden." - }, { "id": "api.team.invite_guests_to_channels.license.error", "translation": "Deine Lizenz unterstützt Gastkonten nicht" diff --git a/server/i18n/en_AU.json b/server/i18n/en_AU.json index 9bb7f749bd..c686ba1acc 100644 --- a/server/i18n/en_AU.json +++ b/server/i18n/en_AU.json @@ -9026,50 +9026,6 @@ "id": "app.job.get_all_jobs_by_type_and_status.app_error", "translation": "Unable to get the all jobs by type and status." }, - { - "id": "api.templates.server_inactivity_title", - "translation": "Unlock increased productivity with these awesome features" - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "Hey {{.Name}}, your Mattermost server has been a bit inactive. Would you like to take a look at some features that can help lighten your team's workload?" - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "Open Mattermost to increase your team’s productivity!" - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "Manage tasks using " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "Workflow management with " - }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "Guest Access to specified " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "Come and check it out!" - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "Open Mattermost" - }, - { - "id": "Playbooks", - "translation": "Playbooks" - }, - { - "id": "Channels", - "translation": "Channels" - }, - { - "id": "Boards", - "translation": "Boards" - }, { "id": "app.prepackged-plugin.invalid_version.app_error", "translation": "A prepackged plugin version could not be parsed." @@ -9166,10 +9122,6 @@ "id": "api.elasticsearch.test_elasticsearch_settings_nil.app_error", "translation": "Elasticsearch settings has unset values." }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "You received this one-time email because your Mattermost server was inactive for more than {{.Hours}} hours. This email was automatically generated by your Mattermost server." - }, { "id": "app.recent_searches.app_error", "translation": "An error occurred while fetching recent searches" @@ -9518,10 +9470,6 @@ "id": "model.insights.get_start_of_day_for_time_range.time_range.app_error", "translation": "Invalid time range." }, - { - "id": "app.plugin.product_mode.app_error", - "translation": "Plugin {{.Name}} cannot be enabled in product mode." - }, { "id": "api.team.invite_guests_to_channels.license.error", "translation": "Your workspace licence does not support guest accounts" diff --git a/server/i18n/es.json b/server/i18n/es.json index 0e1791f125..6a8f3c43ce 100644 --- a/server/i18n/es.json +++ b/server/i18n/es.json @@ -8975,10 +8975,6 @@ "id": "model.config.is_valid.elastic_search.bulk_indexing_batch_size.app_error", "translation": "El tamaño del lote de indexación masiva de Elasticsearch debe ser al menos de {{.BatchSize}}." }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "Recibiste este correo electrónico único porque tu servidor Mattermost estuvo inactivo durante más de {{.Hours}} horas. Este correo electrónico fue generado automáticamente por tu servidor Mattermost." - }, { "id": "api.custom_groups.no_remote_id", "translation": " " @@ -8987,10 +8983,6 @@ "id": "app.system.get_onboarding_request.app_error", "translation": "No se pudo obtener el estado de finalización de inducción." }, - { - "id": "Boards", - "translation": " " - }, { "id": "app.custom_group.unique_name", "translation": " " @@ -9059,26 +9051,6 @@ "id": "api.getThreadsForUser.bad_only_params", "translation": " " }, - { - "id": "api.templates.server_inactivity_button", - "translation": " " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "¡Ven y dale un vistazo!" - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": " " - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "Hey {{.Name}}, notamos que tu servidor Mattermost está acumulando algo de polvo. Da un vistazo a algunas características que pueden aligerar la carga de trabajo de tu equipo." - }, - { - "id": "api.templates.server_inactivity_title", - "translation": " " - }, { "id": "app.job.get_all_jobs_by_type_and_status.app_error", "translation": "No se pudo obtener todos los jobs por tipo y estado." @@ -9115,14 +9087,6 @@ "id": "api.elasticsearch.test_elasticsearch_settings_nil.app_error", "translation": "Los ajustes de Búsqueda Elástica tienen valores no establecidos." }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": " " - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "¡Ven y abre Mattermost para aumentar la productividad de tu equipo!" - }, { "id": "api.team.invite_members_to_team_and_channels.invalid_body.app_error", "translation": "Cuerpo de solicitud no válido." @@ -9207,10 +9171,6 @@ "id": "api.templates.invite_team_and_channel_body.title", "translation": "{{ .SenderName }} te invitó a unirte al Canal {{ .ChannelName }} en el Equipo {{ .TeamDisplayName}}" }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": " " - }, { "id": "api.templates.cloud_upgrade_confirmation.title", "translation": "¡Ahora estás actualizado!" @@ -9227,14 +9187,6 @@ "id": "api.team.invite_members.unable_to_send_email_with_defaults.app_error", "translation": " " }, - { - "id": "Playbooks", - "translation": " " - }, - { - "id": "Channels", - "translation": " " - }, { "id": "api.user.authorize_oauth_user.saml_response_too_long.app_error", "translation": " " @@ -9487,10 +9439,6 @@ "id": "app.post.get_top_dms_for_user_since.app_error", "translation": "No es posible obtener los DMs principales para el usuario." }, - { - "id": "app.plugin.product_mode.app_error", - "translation": "El plugin {{.Name}} no se pudo activar en el modo producto." - }, { "id": "app.notify_admin.send_notification_post.app_error", "translation": "No es posible enviar la publicación de notificación." diff --git a/server/i18n/fr.json b/server/i18n/fr.json index 50b5d159c8..77720df20d 100644 --- a/server/i18n/fr.json +++ b/server/i18n/fr.json @@ -8571,34 +8571,6 @@ "id": "api.license.request_renewal_link.cannot_renew_on_cws", "translation": "Le renouvellement de cette licence sur le portail n'est pas possible" }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "Bonjour {{.Name}}, nous avons remarqué que votre serveur Mattermost collecte un peu la poussière. Découvrez quelques fonctionnalités qui peuvent vous aider à alléger la charge de travail de votre équipe." - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "Gérez des tâches en utilisant " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "Venez et regardez ça !" - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "Ouvrir Mattermost" - }, - { - "id": "Playbooks", - "translation": "Playbooks" - }, - { - "id": "Channels", - "translation": "Channels" - }, - { - "id": "Boards", - "translation": "Boards" - }, { "id": "app.prepackged-plugin.invalid_version.app_error", "translation": "La version du plugin pré-packagé n'a pas pu être traitée." @@ -8755,26 +8727,6 @@ "id": "api.user.view_archived_channels.get_posts_for_channel.app_error", "translation": "Impossible de retrouver les messages pour un canal archivé" }, - { - "id": "api.templates.server_inactivity_title", - "translation": "Augmentez votre productivité en déverrouillant ces fonctionnalités géniales" - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "Ouvrez Mattermost pour augmenter la productivité de votre équipe !" - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "Gestion du déroulement des opérations avec " - }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "Accès des invités à l'espace spécifié " - }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "Vous avez reçu ce courriel unique parce que votre serveur Mattermost est inactif depuis plus de {{.Hours}} heures. Ce courriel a été généré automatiquement par votre serveur Mattermost." - }, { "id": "api.templates.invite_team_and_channels_subject", "translation": "[{{ .SiteName}}] {{ .SenderName }} vous a invité à rejoindre {{ .ChannelsLen }} canaux de l'équipe {{ .TeamDisplayName }}" diff --git a/server/i18n/hu.json b/server/i18n/hu.json index 11194850f6..e66cb9ae7f 100644 --- a/server/i18n/hu.json +++ b/server/i18n/hu.json @@ -9019,50 +9019,6 @@ "id": "app.member_count", "translation": "hiba a tagok számának lekérdezésében" }, - { - "id": "Boards", - "translation": "Táblák" - }, - { - "id": "Channels", - "translation": "Csatornák" - }, - { - "id": "Playbooks", - "translation": "Forgatókönyvek" - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "Mattermost megnyitása" - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "Helló {{.Name}}, észrevettük, hogy a Mattermost szervered egy kicsit porosodik. Vess egy pillantást néhány funkcióra, amelyek segíthetnek könnyíteni csapatod munkaterhét." - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "Nyissa meg a Mattermostot, hogy növelje csapata termelékenységét!" - }, - { - "id": "api.templates.server_inactivity_title", - "translation": "Növelje a termelékenységet ezekkel a fantasztikus funkciókkal" - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "Feladatok kezelése a " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "Munkafolyamatok kezelése a " - }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "Vendég hozzáférés a megadott " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "Jöjjön és nézze meg!" - }, { "id": "app.job.get_all_jobs_by_type_and_status.app_error", "translation": "Nem lehet lekérni az összes munkát típus és státusz szerint." @@ -9163,10 +9119,6 @@ "id": "api.elasticsearch.test_elasticsearch_settings_nil.app_error", "translation": "Az Elasticsearch beállításában nem mentett értékek vannak." }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "Ezt az egyszeri e-mailt azért kapta, mert a Mattermost szervere több mint {{.Hours}} órán keresztül inaktív volt. Ezt az e-mailt a Mattermost szervere automatikusan generálta." - }, { "id": "api.file.cloud_upload.app_error", "translation": "Az mmctl segítségével történő feltöltés egy felhő alapú példányra nem támogatott. Kérjük, tekintse meg a dokumentációt itt: https://docs.mattermost.com/manage/cloud-data-export.html." diff --git a/server/i18n/it.json b/server/i18n/it.json index 14f201c891..0129b143eb 100644 --- a/server/i18n/it.json +++ b/server/i18n/it.json @@ -7359,14 +7359,6 @@ "id": "api.upgrade_to_enterprise.invalid-user.app_error", "translation": " " }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": " " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": " " - }, { "id": "api.templates.email_footer_v2", "translation": " " @@ -7479,10 +7471,6 @@ "id": "api.command_share.fetch_remote_status.error", "translation": " " }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": " " - }, { "id": "api.templates.invite_team_and_channels_body.title", "translation": " " @@ -7527,10 +7515,6 @@ "id": "api.command_remote.remote_add_remove.help", "translation": " " }, - { - "id": "api.templates.server_inactivity_title", - "translation": " " - }, { "id": "api.templates.invite_team_and_channels_subject", "translation": " " @@ -7863,10 +7847,6 @@ "id": "api.templates.invite_body_guest.subTitle", "translation": " " }, - { - "id": "Playbooks", - "translation": " " - }, { "id": "api.command_custom_status.hint", "translation": " " @@ -8199,10 +8179,6 @@ "id": "api.system.update_notices.clear_failed", "translation": " " }, - { - "id": "api.templates.server_inactivity_info", - "translation": " " - }, { "id": "app.system.complete_onboarding_request.no_first_user", "translation": " " @@ -8211,14 +8187,6 @@ "id": "app.user.get_unread_count.app_error", "translation": " " }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": " " - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": " " - }, { "id": "app.team.join_user_to_team.save_member.conflict.app_error", "translation": " " @@ -8419,18 +8387,10 @@ "id": "model.reaction.is_valid.update_at.app_error", "translation": " " }, - { - "id": "Boards", - "translation": " " - }, { "id": "app.notification.footer.info", "translation": " " }, - { - "id": "api.templates.server_inactivity_button", - "translation": " " - }, { "id": "api.command_share.remote_id_invalid.error", "translation": " " @@ -8499,10 +8459,6 @@ "id": "api.post.send_notification_and_forget.push_comment_on_crt_thread_dm", "translation": " " }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": " " - }, { "id": "import_process.worker.do_job.missing_jsonl", "translation": " " @@ -9231,10 +9187,6 @@ "id": "api.command_custom_status.clear.app_error", "translation": " " }, - { - "id": "Channels", - "translation": " " - }, { "id": "api.admin.add_certificate.parseform.app_error", "translation": " " diff --git a/server/i18n/ja.json b/server/i18n/ja.json index f7b3975155..c30ce9288b 100644 --- a/server/i18n/ja.json +++ b/server/i18n/ja.json @@ -8983,18 +8983,6 @@ "id": "api.custom_groups.count_err", "translation": "グループのカウント中にエラーが発生しました" }, - { - "id": "Playbooks", - "translation": "Playbooks" - }, - { - "id": "Channels", - "translation": "チャンネル" - }, - { - "id": "Boards", - "translation": "Boards" - }, { "id": "model.emoji.system_emoji_name.app_error", "translation": "既存のシステム絵文字名と名前が競合しています。" @@ -9019,38 +9007,6 @@ "id": "app.custom_group.unique_name", "translation": "グループ名が重複しています" }, - { - "id": "api.templates.server_inactivity_title", - "translation": "これらの機能による生産性の向上をアンロックする" - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "{{.Name}} さん、あなたのMattermostサーバーが少し埃をかぶっていることに気づきました。チームの作業負荷を軽減するのに役立ついくつかの機能を確認してみてください。" - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "Mattermostを開いてチームの生産性を向上しましょう!" - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "タスク管理のための " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "ワークフロー管理のための " - }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "ゲストアクセス可能な " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "ぜひご覧ください!" - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "Mattermostを開く" - }, { "id": "api.license_error", "translation": "APIエンドポイントにはライセンスが必要です" @@ -9163,10 +9119,6 @@ "id": "api.elasticsearch.test_elasticsearch_settings_nil.app_error", "translation": "Elasticsearchの設定に未設定の値があります。" }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "あなたの Mattermost サーバが {{.Hours}} 時間以上アクティブでなかったため、このワンタイム電子メールが送信されました。この電子メールは、Mattermost サーバによって自動的に生成されたものです。" - }, { "id": "app.recent_searches.app_error", "translation": "最近の検索履歴を取得する際にエラーが発生しました" @@ -9499,10 +9451,6 @@ "id": "model.group.name.reserved_name.app_error", "translation": "グループ名は予約語として既に登録されています" }, - { - "id": "app.plugin.product_mode.app_error", - "translation": "プラグイン {{.Name}} はプロダクトモードでは有効化できません。" - }, { "id": "app.last_accessible_file.app_error", "translation": "最後にアクセスしたファイルの取得エラー" diff --git a/server/i18n/ko.json b/server/i18n/ko.json index 6e71b18d58..0e91deea0c 100644 --- a/server/i18n/ko.json +++ b/server/i18n/ko.json @@ -7859,10 +7859,6 @@ "id": "bleveengine.delete_post_files.error", "translation": "게시된 파일을 삭제하지 못했습니다." }, - { - "id": "Boards", - "translation": "보드" - }, { "id": "api.elasticsearch.test_elasticsearch_settings_nil.app_error", "translation": "Elasticsearch 설정에 설정되지 않은 값이 있습니다." @@ -7887,14 +7883,6 @@ "id": "api.cloud.notify_admin_to_upgrade_error.already_notified", "translation": "이미 관리자에게 통지됨" }, - { - "id": "Playbooks", - "translation": "플레이북" - }, - { - "id": "Channels", - "translation": "채널" - }, { "id": "api.custom_groups.feature_disabled", "translation": "사용자 정의 그룹 기능은 비활성화되어 있습니다" diff --git a/server/i18n/nl.json b/server/i18n/nl.json index 85fa7448a6..46f05f6239 100644 --- a/server/i18n/nl.json +++ b/server/i18n/nl.json @@ -9026,50 +9026,6 @@ "id": "app.job.get_all_jobs_by_type_and_status.app_error", "translation": "Het lukt niet om alle jobs op type en status op te halen." }, - { - "id": "api.templates.server_inactivity_title", - "translation": "Verhoog jouw productiviteit met deze geweldige functies" - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "Hey {{.Naam}}, we hebben gemerkt dat jouw Mattermost server een beetje stof aan het verzamelen is. Kijk eens naar enkele functies die kunnen helpen om de werklast van jouw team te verlichten." - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "Open Mattermost om de productiviteit van je team te verhogen!" - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "Beheer taken met " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "Workflowbeheer met " - }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "Gast-toegang tot gespecificeerd(e) " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "Kom maar eens kijken!" - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "Mattermost openen" - }, - { - "id": "Playbooks", - "translation": "Playbooks" - }, - { - "id": "Channels", - "translation": "Kanalen" - }, - { - "id": "Boards", - "translation": "Boards" - }, { "id": "api.team.invite_members.unable_to_send_email_with_defaults.app_error", "translation": "SMTP is niet geconfigureerd in Systeem Console" @@ -9162,10 +9118,6 @@ "id": "api.elasticsearch.test_elasticsearch_settings_nil.app_error", "translation": "De instellingen van Elasticsearch bevat niet-ingestelde waarden." }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "Je hebt deze eenmalige email ontvangen omdat jouw Mattermost server inactief was voor meer dan {{.Hours}} uur. Deze e-mail werd automatisch aangemaakt door jouw Mattermost server." - }, { "id": "api.templates.cloud_upgrade_confirmation.title", "translation": "Je bent nu geüpgraded!" @@ -9502,10 +9454,6 @@ "id": "model.group.name.reserved_name.app_error", "translation": "groepsnaam bestaat al als een gereserveerde naam" }, - { - "id": "app.plugin.product_mode.app_error", - "translation": "Plugin {{.Name}} kan niet worden ingeschakeld in de productmodus." - }, { "id": "app.last_accessible_file.app_error", "translation": "Fout bij het ophalen van het laatst toegankelijke bestand" diff --git a/server/i18n/pl.json b/server/i18n/pl.json index b123990e90..25a16ea5db 100644 --- a/server/i18n/pl.json +++ b/server/i18n/pl.json @@ -9023,50 +9023,6 @@ "id": "api.custom_groups.count_err", "translation": "błąd liczenia grup" }, - { - "id": "api.templates.server_inactivity_title", - "translation": "Odblokuj zwiększoną produktywność dzięki tym wspaniałym funkcjom" - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "Hej {{.Name}}, zauważyliśmy, że twój serwer Mattermost zbiera trochę kurzu. Zapoznaj się z kilkoma funkcjami, które pomogą odciążyć Twój zespół." - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "Otwórz Mattermost, aby zwiększyć produktywność swojego zespołu!" - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "Zarządzaj zadaniami za pomocą " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "Zarządzanie przepływem pracy z " - }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "Dostęp gości do określenia " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "Przyjdź i sprawdź to!" - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "Otwórz Mattermost" - }, - { - "id": "Playbooks", - "translation": "Playbooki" - }, - { - "id": "Channels", - "translation": "Kanały" - }, - { - "id": "Boards", - "translation": "Tablice" - }, { "id": "model.oauth.is_valid.mattermost_app_id.app_error", "translation": "Maksymalna długość identyfikatora MattermostAppID wynosi 32 znaki." @@ -9171,10 +9127,6 @@ "id": "api.elasticsearch.test_elasticsearch_settings_nil.app_error", "translation": "Ustawienia Elasticsearch mają nieustawione wartości." }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "Otrzymałeś tę jednorazową wiadomość e-mail, ponieważ Twój serwer Mattermost był nieaktywny przez ponad {{.Hours}} godzin. Ta wiadomość e-mail została automatycznie wygenerowana przez serwer Mattermost." - }, { "id": "api.file.cloud_upload.app_error", "translation": "Przesyłanie danych do instancji Chmury za pomocą mmctl nie jest obsługiwane. Proszę sprawdzić dokumentację tutaj: https://docs.mattermost.com/manage/cloud-data-export.html." @@ -9511,10 +9463,6 @@ "id": "model.group.name.reserved_name.app_error", "translation": "nazwa grupy już istnieje jako nazwa zastrzeżona" }, - { - "id": "app.plugin.product_mode.app_error", - "translation": "Wtyczka {{.Name}} nie może być włączona w trybie produktu." - }, { "id": "api.team.invite_guests_to_channels.license.error", "translation": "Twoja licencja nie wspiera kont gości" diff --git a/server/i18n/pt-BR.json b/server/i18n/pt-BR.json index 63dcbcc1ce..48f679a2be 100644 --- a/server/i18n/pt-BR.json +++ b/server/i18n/pt-BR.json @@ -8619,18 +8619,6 @@ "id": "api.cloud.notify_admin_to_upgrade_error.already_notified", "translation": "Administrador já notificado" }, - { - "id": "Channels", - "translation": "Canais" - }, - { - "id": "Boards", - "translation": "Quadros" - }, - { - "id": "Playbooks", - "translation": "Playbooks" - }, { "id": "api.cloud.delinquency_email.missing_email_to_trigger", "translation": "Campos faltando para envio de email." diff --git a/server/i18n/ru.json b/server/i18n/ru.json index bc21184315..9a214093d2 100644 --- a/server/i18n/ru.json +++ b/server/i18n/ru.json @@ -8967,18 +8967,6 @@ "id": "api.custom_groups.feature_disabled", "translation": "функция пользовательских групп отключена" }, - { - "id": "Playbooks", - "translation": "Сценарии" - }, - { - "id": "Channels", - "translation": "Каналы" - }, - { - "id": "Boards", - "translation": "Доски" - }, { "id": "api.error_get_first_admin_complete_setup", "translation": "Ошибка при попытке получить первую завершенную настройку администратора из магазина." @@ -9035,34 +9023,6 @@ "id": "api.user.authorize_oauth_user.saml_response_too_long.app_error", "translation": "Ответ SAML слишком длинный" }, - { - "id": "api.templates.server_inactivity_title", - "translation": "Откройте для себя повышенную производительность с помощью этих замечательных функций" - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "Привет, {{.Name}}, мы заметили, что Ваш сервер Mattermost собирает немного пыли. Взгляните на некоторые функции, которые могут облегчить рабочую нагрузку в Вашей команде." - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "Откройте все возможности Mattermost, чтобы повысить производительность вашей команды!" - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "Управляйте задачами с помощью " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "Управление рабочим процессом с " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "Приходите и проверьте это!" - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "Открыть Mattermost" - }, { "id": "api.team.invite_members.unable_to_send_email_with_defaults.app_error", "translation": "SMTP не настроен в Системной Консоли" @@ -9079,10 +9039,6 @@ "id": "api.error_set_first_admin_complete_setup", "translation": "Ошибка при попытке сохранить первую полную настройку администратора в магазине." }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "Гостевой доступ к указанному " - }, { "id": "model.oauth.is_valid.mattermost_app_id.app_error", "translation": "Максимальная длина MattermostAppID — 32 символа." @@ -9307,10 +9263,6 @@ "id": "app.post.analytics_teams_count.app_error", "translation": "Не удалось получить сведения об использовании команд" }, - { - "id": "app.plugin.product_mode.app_error", - "translation": "Плагин {{.Name}} не может быть включен в продуктовом режиме." - }, { "id": "app.notify_admin.send_notification_post.app_error", "translation": "Невозможно отправить сообщение с уведомлением." @@ -9371,10 +9323,6 @@ "id": "app.cloud.get_cloud_products.app_error", "translation": "Не удалось получить облачные продукты" }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "Вы получили это одноразовое письмо, потому что ваш сервер Mattermost был неактивен более {{.Hours}} часов. Это письмо было автоматически сгенерировано вашим сервером Mattermost." - }, { "id": "api.templates.delinquency_90.title", "translation": "Ваше рабочее пространство Mattermost было понижено в статусе" diff --git a/server/i18n/sv.json b/server/i18n/sv.json index 2b8f6eced0..f5a3da2887 100644 --- a/server/i18n/sv.json +++ b/server/i18n/sv.json @@ -8970,18 +8970,6 @@ "id": "app.system.complete_onboarding_request.app_error", "translation": "Misslyckades att tolka onboarding-anropet." }, - { - "id": "Playbooks", - "translation": "Playbooks" - }, - { - "id": "Channels", - "translation": "Kanaler" - }, - { - "id": "Boards", - "translation": "Boards" - }, { "id": "api.custom_groups.no_remote_id", "translation": "remote_id måste vara tomt för anpassade grupper" @@ -9070,42 +9058,6 @@ "id": "app.channel.get_file_count.app_error", "translation": "Det går inte att få fram antalet filer i kanalen" }, - { - "id": "api.templates.server_inactivity_title", - "translation": "Öka produktiviteten med dessa fantastiska funktioner" - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "Hej {{.Name}}, vi ser att din Mattermost-server samlat lite damm. Ta en titt på några funktioner som kan hjälpa till att lätta på arbetsbördan för ditt team." - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "Öppna Mattermost för att öka teamets produktivitet!" - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "Hantera uppgifter med hjälp av " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "Hantera arbetsflöden med " - }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "Gäståtkomst till specificerade " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "Kom och kolla in det!" - }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "Du fick det här engångsmejlet eftersom din Mattermost-server har varit inaktiv i mer än {{.Hours}} timmar. Det här e-postmeddelandet genererades automatiskt av din Mattermost-server." - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "Öppna Mattermost" - }, { "id": "api.templates.invite_team_and_channels_subject", "translation": "[{{ .SiteName }}] {{ .SenderName }} bjöd in dig att ansluta till {{ .ChannelsLen }} kanaler i teamet {{ .TeamDisplayName }}" @@ -9522,10 +9474,6 @@ "id": "model.insights.get_start_of_day_for_time_range.time_range.app_error", "translation": "Ogiltigt tidsintervall." }, - { - "id": "app.plugin.product_mode.app_error", - "translation": "Plugin {{.Name}} kan inte aktiveras i produktionsläge." - }, { "id": "app.collection.add_collection.exists.app_error", "translation": "Samlingstypen finns redan." diff --git a/server/i18n/tr.json b/server/i18n/tr.json index 1c9448505c..84e7ffedc7 100644 --- a/server/i18n/tr.json +++ b/server/i18n/tr.json @@ -9022,50 +9022,6 @@ "id": "api.custom_groups.count_err", "translation": "gruplar sayılırken sorun çıktı" }, - { - "id": "api.templates.server_inactivity_title", - "translation": "Bu harika özelliklerle üretkenliğinizi artırın" - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "Ekibinizin üretkenliğini arttırmak için Mattermost açın!" - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "Merhaba {{.Name}}, Mattermost sunucunuzun biraz toz tuttuğunu fark ettik. Ekibinizin iş yükünü hafifletmeye yardımcı olabilecek bazı özelliklere göz atın." - }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "Belirtilen konuk erişimi " - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "Görev yönetimi " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "İş akışı yönetimi " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "Gelin ve inceleyin!" - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "Mattermost uygulamasını aç" - }, - { - "id": "Playbooks", - "translation": "Senaryolar" - }, - { - "id": "Channels", - "translation": "Kanallar" - }, - { - "id": "Boards", - "translation": "Panolar" - }, { "id": "app.job.get_all_jobs_by_type_and_status.app_error", "translation": "Türe ve duruma göre tüm görevler alınamadı." @@ -9166,10 +9122,6 @@ "id": "api.templates.cloud_upgrade_confirmation.subject", "translation": "Mattermost üst tarifeye geçme onayı" }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "Bu bir kerelik e-posta Mattermost sunucunuz {{.Hours}} saatten uzun süredir etkin olmadığı için gönderildi. Bu e-posta Mattermost sunucunuz tarafından otomatik olarak oluşturuldu." - }, { "id": "api.elasticsearch.test_elasticsearch_settings_nil.app_error", "translation": "Elasticsearch yapılandırmasında ayarlanmamış değerler var." @@ -9510,10 +9462,6 @@ "id": "model.group.name.reserved_name.app_error", "translation": "aynı adlı bir grup zaten sistem kullanımına ayrılmış bir ad olarak var" }, - { - "id": "app.plugin.product_mode.app_error", - "translation": "{{.Name}} uygulama eki ürün kipinde etkinleştirilemez." - }, { "id": "api.team.invite_guests_to_channels.license.error", "translation": "Lisansınız konuk hesaplarının kullanılmasını desteklemiyor" diff --git a/server/i18n/uk.json b/server/i18n/uk.json index bce734f746..b63779f26f 100644 --- a/server/i18n/uk.json +++ b/server/i18n/uk.json @@ -6847,10 +6847,6 @@ "id": "api.back_to_app", "translation": "Повернутися до {{.SiteName}}" }, - { - "id": "Channels", - "translation": "Канали" - }, { "id": "api.cloud.cws_webhook_event_missing_error", "translation": "Подія Webhook не оброблена. Або вона відсутня, або недійсна." @@ -6879,14 +6875,6 @@ "id": "api.acknowledgement.delete.archived_channel.app_error", "translation": "Ви не можете видалити підтвердження в заархівованому каналі." }, - { - "id": "Playbooks", - "translation": "Сценарії" - }, - { - "id": "Boards", - "translation": "Дошки" - }, { "id": "api.command_remote.invite.help", "translation": "Запросіть безпечне з'єднання" diff --git a/server/i18n/zh-CN.json b/server/i18n/zh-CN.json index 11f9a677c4..b5bd72476a 100644 --- a/server/i18n/zh-CN.json +++ b/server/i18n/zh-CN.json @@ -8999,38 +8999,6 @@ "id": "api.user.authorize_oauth_user.saml_response_too_long.app_error", "translation": "SAML的请求信息太长" }, - { - "id": "api.templates.server_inactivity_title", - "translation": "解锁这些令人敬佩的、提高生产力的功能" - }, - { - "id": "api.templates.server_inactivity_subtitle", - "translation": "嗨, {{.Name}}, 我们注意到您的 Mattermost 服务器集了一些“灰尘”(有一段时间没有维护了),快来看看可以帮助减轻团队工作量的一些功能." - }, - { - "id": "api.templates.server_inactivity_subject", - "translation": "快来打开 Mattermost 以提高您团队的生产力!" - }, - { - "id": "api.templates.server_inactivity_info_bullet2", - "translation": "管理任务由 " - }, - { - "id": "api.templates.server_inactivity_info_bullet1", - "translation": "工作流管理于 " - }, - { - "id": "api.templates.server_inactivity_info_bullet", - "translation": "指定客户专访 " - }, - { - "id": "api.templates.server_inactivity_info", - "translation": "快来看看吧!" - }, - { - "id": "api.templates.server_inactivity_button", - "translation": "打开 Mattermost" - }, { "id": "api.templates.invite_team_and_channels_subject", "translation": "[{{ .SiteName }}] {{ .SenderName }} 邀请您加入 {{ .TeamDisplayName }} 团队的 {{ .ChannelsLen }} 频道组" @@ -9127,18 +9095,6 @@ "id": "api.custom_groups.count_err", "translation": "统计“组”时出现错误" }, - { - "id": "Playbooks", - "translation": "规划书" - }, - { - "id": "Channels", - "translation": "频道" - }, - { - "id": "Boards", - "translation": "面板" - }, { "id": "model.oauth.is_valid.mattermost_app_id.app_error", "translation": "MattermostAppID 的最大长度为 32 个字符。" @@ -9171,10 +9127,6 @@ "id": "app.insights.feature_disabled", "translation": "Insights 功能已禁用。" }, - { - "id": "api.templates.server_inactivity_footer_disclaimer", - "translation": "您收到这封一次性电子邮件是因为您的 Mattermost 服务器处于非活动状态超过 {{.Hours}} 小时。 本电子邮件是由您的 Mattermost 服务器自动生成。" - }, { "id": "api.file.cloud_upload.app_error", "translation": "不支持通过 mmctl 上传到 Cloud 实例。 请在此处查看文档:https://docs.mattermost.com/manage/cloud-data-export.html。" @@ -9687,10 +9639,6 @@ "id": "app.post_prority.get_for_post.app_error", "translation": "无法取得消息的优先级" }, - { - "id": "app.plugin.product_mode.app_error", - "translation": "在生产模式中无法启用 {{.Name}} 插件。" - }, { "id": "app.notify_admin.send_notification_post.app_error", "translation": "无法发送通知消息。" diff --git a/server/i18n/zh-TW.json b/server/i18n/zh-TW.json index 780ee87973..e677cec709 100644 --- a/server/i18n/zh-TW.json +++ b/server/i18n/zh-TW.json @@ -7247,10 +7247,6 @@ "id": "api.back_to_app", "translation": "返回至 {{.SiteName}}" }, - { - "id": "Channels", - "translation": "頻道" - }, { "id": "api.cloud.app_error", "translation": "雲端 API 請求時發生內部錯誤。" diff --git a/webapp/channels/src/i18n/bg.json b/webapp/channels/src/i18n/bg.json index c5331d8e9c..7a45713834 100644 --- a/webapp/channels/src/i18n/bg.json +++ b/webapp/channels/src/i18n/bg.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Корпоративна версия", "about.hash": "Хеш на компилация:", "about.hashee": "Хеш на EE компилация:", - "about.hashwebapp": "Webapp билд хеш:", "about.licensed": "Лицензиран на:", "about.notice": "Използването на Mattermost е възможно благодарение на софтуер с отворен код използван в нашите сървърно, настолно и мобилно приложения.", "about.privacy": "Политика за поверителност", diff --git a/webapp/channels/src/i18n/de.json b/webapp/channels/src/i18n/de.json index 01990e3010..cabaa6ab80 100644 --- a/webapp/channels/src/i18n/de.json +++ b/webapp/channels/src/i18n/de.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Enterprise Edition", "about.hash": "Build Hashwert:", "about.hashee": "EE Build Hashwert:", - "about.hashwebapp": "Webapp-Build-Hash:", "about.licensed": "Lizenziert für:", "about.notice": "Mattermost wird durch Open Source Software möglich gemacht, die in unseren Server-, Desktop- und mobilen Apps verwendet wird.", "about.privacy": "Datenschutzbedingungen", @@ -4156,22 +4155,12 @@ "modal.manual_status.title_offline": "Dein Status wurde auf \"Offline\" gesetzt", "modal.manual_status.title_ooo": "Dein Status ist auf \"Nicht im Büro\" gesetzt", "more.details": "Mehr Details", - "more_channels.channel_purpose": "Kanal-Informationen: Mitgliedschaftsindikator: Beigetreten, Mitglieder {memberCount}, Zweck: {channelPurpose}", - "more_channels.count": "{count} Ergebnisse", - "more_channels.count_one": "1 Ergebnis", "more_channels.count_zero": "Keine Ergebnisse", "more_channels.create": "Kanal erstellen", - "more_channels.hide_joined": "Verbundene Kanäle ausblenden", - "more_channels.hide_joined_checked": "Kontrollkästchen Verbundene Kanäle ausblenden, aktiviert", - "more_channels.hide_joined_not_checked": "Kontrollkästchen Verbundene Kanäle ausblenden, deaktiviert", "more_channels.joined": "Verknüpft", - "more_channels.membership_indicator": "Mitgliedschaftsindikator: Beigetreten", "more_channels.next": "Weiter", - "more_channels.noArchived": "Keine archivierten Kanäle", "more_channels.noMore": "Keine Ergebnisse für \"{text}\"", - "more_channels.noPublic": "Keine öffentlichen Kanäle", "more_channels.prev": "Zurück", - "more_channels.searchError": "Versuche, nach anderen Stichworten zu suchen, auf Tippfehlern zu prüfen oder die Filter anzupassen.", "more_channels.show_archived_channels": "Anzeigen: Archivierte Kanäle", "more_channels.show_public_channels": "Anzeigen: Öffentliche Kanäle", "more_channels.title": "Weitere Kanäle", diff --git a/webapp/channels/src/i18n/en_AU.json b/webapp/channels/src/i18n/en_AU.json index 66c0e85690..2906491d72 100644 --- a/webapp/channels/src/i18n/en_AU.json +++ b/webapp/channels/src/i18n/en_AU.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Enterprise Edition", "about.hash": "Build Hash:", "about.hashee": "EE Build Hash:", - "about.hashwebapp": "Webapp Build Hash:", "about.licensed": "Licensed to:", "about.notice": "Mattermost is made possible by the open source software used in our server, desktop and mobile apps.", "about.privacy": "Privacy Policy", diff --git a/webapp/channels/src/i18n/es.json b/webapp/channels/src/i18n/es.json index 28de93f5e2..bc69dc4c80 100644 --- a/webapp/channels/src/i18n/es.json +++ b/webapp/channels/src/i18n/es.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Edición Empresarial E1", "about.hash": "Hash de compilación:", "about.hashee": "Hash de compilación de EE:", - "about.hashwebapp": "Hash de compilación de la App Web:", "about.licensed": "Licenciado a:", "about.notice": "Mattermost es hecho posible gracias a software de código libre utilizado en nuestro servidor, desktop y apps móviles.", "about.privacy": "Política de Privacidad", diff --git a/webapp/channels/src/i18n/fa.json b/webapp/channels/src/i18n/fa.json index 90132c93a1..7a5e231090 100644 --- a/webapp/channels/src/i18n/fa.json +++ b/webapp/channels/src/i18n/fa.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "نسخه تجاری", "about.hash": "هش ساخت:", "about.hashee": "هش ساخت نسخه تجاری:", - "about.hashwebapp": "هش بیلد وب‌اپ:", "about.licensed": "مجوز داده شده به:", "about.notice": "Mattermost یک نرم افزار متن باز توسه یافته است . جهت بررسی نسخه ها در server و نسخه دسکتاپ در desktop و اپلیکشن موبایل در mobile اطلاع رسانی می شود.", "about.privacy": "سیاست حفظ حریم خصوصی", diff --git a/webapp/channels/src/i18n/fr.json b/webapp/channels/src/i18n/fr.json index 0b4cc9471e..bc8beb3640 100644 --- a/webapp/channels/src/i18n/fr.json +++ b/webapp/channels/src/i18n/fr.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Édition Entreprise", "about.hash": "Hash de version :", "about.hashee": "Hash de version EE :", - "about.hashwebapp": "Hash de la webapp :", "about.licensed": "Licence accordée à :", "about.notice": "Mattermost est rendu possible grâce aux logiciels open source utilisés dans notre serveur, applications de bureau et applications mobiles.", "about.privacy": "Politique de respect de la vie privée", diff --git a/webapp/channels/src/i18n/hu.json b/webapp/channels/src/i18n/hu.json index cf69f79c4c..072b7fc7e5 100644 --- a/webapp/channels/src/i18n/hu.json +++ b/webapp/channels/src/i18n/hu.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Enterprise Kiadás", "about.hash": "Kiadás ujjlenyomata:", "about.hashee": "EE kiadás ujjlenyomata:", - "about.hashwebapp": "Webapp kiadás ujjlenyomat:", "about.licensed": "Licenc tulajdonosa:", "about.notice": "A Mattermost rendszert a szerver, asztali és mobilalkalmazásainkban használt nyílt forráskódú szoftverek teszik lehetővé.", "about.privacy": "Adatvédelmi irányelvek", diff --git a/webapp/channels/src/i18n/it.json b/webapp/channels/src/i18n/it.json index b64ecd9cd4..bcf1c47bc2 100644 --- a/webapp/channels/src/i18n/it.json +++ b/webapp/channels/src/i18n/it.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Edizione Enterprise", "about.hash": "Hash di compilazione:", "about.hashee": "Hash di compilazione EE:", - "about.hashwebapp": "Webapp Build Hash:", "about.licensed": "Licenza concessa a:", "about.notice": "Mattermost è reso possibile dal software open source utilizzato sul nostro server, desktop e mobile apps.", "about.privacy": "Politica sulla privacy", diff --git a/webapp/channels/src/i18n/ja.json b/webapp/channels/src/i18n/ja.json index fee7cc2e97..9c26b7387c 100644 --- a/webapp/channels/src/i18n/ja.json +++ b/webapp/channels/src/i18n/ja.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Enterprise Edition", "about.hash": "ビルドハッシュ値:", "about.hashee": "EEビルドハッシュ値:", - "about.hashwebapp": "Webアプリのビルドハッシュ:", "about.licensed": "ライセンス供給先:", "about.notice": "Mattermostはserverdesktopmobileで使用されているオープンソースソフトウェアによって実現されています。", "about.privacy": "プライバシーポリシー", @@ -4156,22 +4155,10 @@ "modal.manual_status.title_offline": "ステータスが \"オフライン\" になりました", "modal.manual_status.title_ooo": "ステータスが \"外出中\" になりました", "more.details": "もっと詳しく", - "more_channels.channel_purpose": "チャンネル情報: メンバーシップ状況: 加入済, メンバー数 {memberCount} , 目的: {channelPurpose}", - "more_channels.count": "{count}件", - "more_channels.count_one": "1件", - "more_channels.count_zero": "0件", "more_channels.create": "チャンネルを作成する", - "more_channels.hide_joined": "参加したことを表示しない", - "more_channels.hide_joined_checked": "チャンネルに参加したことを表示しないチェックボックスがチェック済です", - "more_channels.hide_joined_not_checked": "チャンネルに参加したことを表示しないチェックボックスがチェックされていません", - "more_channels.joined": "参加済", - "more_channels.membership_indicator": "メンバーシップ状況: 参加済", "more_channels.next": "次へ", - "more_channels.noArchived": "アーカイブされたチャンネルはありません", "more_channels.noMore": "\"{text}\"の結果はありません", - "more_channels.noPublic": "公開チャンネルはありません", "more_channels.prev": "前へ", - "more_channels.searchError": "違うキーワードで検索してみたり、入力ミスを確認したり、フィルター設定を変更して再度お試しください。", "more_channels.show_archived_channels": "表示: アーカイブチャンネル", "more_channels.show_public_channels": "表示: 公開チャンネル", "more_channels.title": "他のチャンネル", diff --git a/webapp/channels/src/i18n/ko.json b/webapp/channels/src/i18n/ko.json index a73022b548..90f55a29e8 100644 --- a/webapp/channels/src/i18n/ko.json +++ b/webapp/channels/src/i18n/ko.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "엔터프라이즈 에디션", "about.hash": "빌드 해쉬:", "about.hashee": "EE 빌드 해쉬:", - "about.hashwebapp": "Webapp 빌드 해쉬:", "about.licensed": "다음 사용자에게 허가되었습니다:", "about.notice": "Mattermost는 서버, 데스크톱 그리고 모바일에서 오픈소스 소프트웨어로 이용 가능합니다.", "about.privacy": "개인정보처리방침", diff --git a/webapp/channels/src/i18n/nl.json b/webapp/channels/src/i18n/nl.json index 2b0c2deccf..b0b4efaf40 100644 --- a/webapp/channels/src/i18n/nl.json +++ b/webapp/channels/src/i18n/nl.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Enterprise-Editie", "about.hash": "Compilatiehash:", "about.hashee": "EE Compilatiehash:", - "about.hashwebapp": "Webapp Build Hash:", "about.licensed": "Licentie verleend aan:", "about.notice": "Mattermost wordt mogelijk gemaakt door de open source software die wordt gebruikt in onze apps server, desktop en mobiel apps.", "about.privacy": "Privacybeleid", diff --git a/webapp/channels/src/i18n/pl.json b/webapp/channels/src/i18n/pl.json index 96eda0f3b4..7d3903cd73 100644 --- a/webapp/channels/src/i18n/pl.json +++ b/webapp/channels/src/i18n/pl.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Edycja Enterprise", "about.hash": "Hash Kompilacji:", "about.hashee": "Hash Kompilacji Enterprise:", - "about.hashwebapp": "Hash Kompilacji Aplikacji Webowej:", "about.licensed": "Licencjonowany dla:", "about.notice": "Mattermost jest został stworzony dzięki oprogramowaniu open source użytym na naszym server, desktop i mobile aplikacje.", "about.privacy": "Polityka prywatności", @@ -4156,22 +4155,12 @@ "modal.manual_status.title_offline": "Twój status został ustawiony na \"Offline\"", "modal.manual_status.title_ooo": "Twój status został ustawiony na \"Poza biurem\"", "more.details": "Więcej informacji", - "more_channels.channel_purpose": "Informacje o kanale: Wskaźnik członkostwa: Dołączyło, liczba członków {memberCount}, Propozycje: {channelPurpose}", - "more_channels.count": "{count} Wyników", - "more_channels.count_one": "1 Wynik", "more_channels.count_zero": "0 Wyników", "more_channels.create": "Stwórz kanał", - "more_channels.hide_joined": "Ukryj dołączonych", - "more_channels.hide_joined_checked": "Pole wyboru Ukryj połączone kanały, zaznaczone", - "more_channels.hide_joined_not_checked": "Pole wyboru Ukryj połączone kanały, nie zaznaczone", "more_channels.joined": "Dołączył", - "more_channels.membership_indicator": "Wskaźnik członkostwa: Dołączył", "more_channels.next": "Dalej", - "more_channels.noArchived": "Brak zarchiwizowanych kanałów", "more_channels.noMore": "Brak wyników dla \"{text}\"", - "more_channels.noPublic": "Brak kanałów publicznych", "more_channels.prev": "Wstecz", - "more_channels.searchError": "Spróbuj wyszukać inne słowa kluczowe, sprawdzić literówki lub dostosować filtry.", "more_channels.show_archived_channels": "Pokaż: Archiwizowane kanały", "more_channels.show_public_channels": "Pokaż: Publiczne kanały", "more_channels.title": "Więcej Kanałów", diff --git a/webapp/channels/src/i18n/pt-BR.json b/webapp/channels/src/i18n/pt-BR.json index 7c727fa2d3..46f0c79dea 100644 --- a/webapp/channels/src/i18n/pt-BR.json +++ b/webapp/channels/src/i18n/pt-BR.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Enterprise Edition", "about.hash": "Hash de Compilação:", "about.hashee": "Hash de Compilação EE:", - "about.hashwebapp": "Webapp Build Hash:", "about.licensed": "Licenciado para:", "about.notice": "Mattermost é possível graças ao software de código aberto usado em nosso servidor, desktop e aplicativos móveis.", "about.privacy": "Política de Privacidade", diff --git a/webapp/channels/src/i18n/ro.json b/webapp/channels/src/i18n/ro.json index 1f71d191a4..c637824455 100644 --- a/webapp/channels/src/i18n/ro.json +++ b/webapp/channels/src/i18n/ro.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Ediția Enterprise", "about.hash": "Construcția Hash:", "about.hashee": "EE Construcția Hash:", - "about.hashwebapp": "Webapp Construcția Hash:", "about.licensed": "Licențiat la:", "about.notice": "Mattermost este făcut posibil de către software-ul open source utilizat în server, desktop și mobil aplicații.", "about.privacy": "Politica de confidentialitate", diff --git a/webapp/channels/src/i18n/ru.json b/webapp/channels/src/i18n/ru.json index 51ff0ffb9c..868acc19cd 100644 --- a/webapp/channels/src/i18n/ru.json +++ b/webapp/channels/src/i18n/ru.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Корпоративная редакция", "about.hash": "Хэш сборки:", "about.hashee": "Хэш сборки EE:", - "about.hashwebapp": "Хэш Веб-Приложения:", "about.licensed": "Лицензия зарегистрирована на:", "about.notice": "Mattermost стал возможен благодаря ПО с открытым исходным кодом, используемом в нашем сервере, настольном клиенте и мобильном приложениях.", "about.privacy": "Политика конфиденциальности", @@ -4156,12 +4155,7 @@ "modal.manual_status.title_offline": "Ваш статус установлен на \"Не в сети\"", "modal.manual_status.title_ooo": "Ваш статус установлен на \"Не на работе\"", "more.details": "Подробнее", - "more_channels.channel_purpose": "Информация о канале: Индикатор членства: Присоединились, Количество участников {memberCount}, Цель: {channelPurpose}", - "more_channels.count": "{count} Результатов", - "more_channels.count_one": "1 Результат", - "more_channels.count_zero": "Нет результатов", "more_channels.create": "Создать канал", - "more_channels.hide_joined": "Скрыть присоединенные", "more_channels.next": "Далее", "more_channels.noMore": "Нет результатов поиска для \"{text}\"", "more_channels.prev": "Предыдущая", diff --git a/webapp/channels/src/i18n/sv.json b/webapp/channels/src/i18n/sv.json index 9ed2615d87..a49a740eb4 100644 --- a/webapp/channels/src/i18n/sv.json +++ b/webapp/channels/src/i18n/sv.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Enterprise-utgåva", "about.hash": "Bygg-hash:", "about.hashee": "EE bygg-hash:", - "about.hashwebapp": "Webapp bygg-hash:", "about.licensed": "Licensierad till:", "about.notice": "Mattermost är möjlig tack vare att både server, skrivbordsapp och mobilapp har öppen källkod.", "about.privacy": "Integritetspolicy", diff --git a/webapp/channels/src/i18n/tr.json b/webapp/channels/src/i18n/tr.json index 4c4e6c1fed..6d3f2eb02d 100644 --- a/webapp/channels/src/i18n/tr.json +++ b/webapp/channels/src/i18n/tr.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Enterprise paketi", "about.hash": "Yapım karması:", "about.hashee": "Enterprise paketi yapım karması:", - "about.hashwebapp": "Web uygulaması yapım karması:", "about.licensed": "Lisans sahibi:", "about.notice": "Kullandığımız açık kaynaklı sunucu, masaüstü ve mobil uygulamalari Mattermost tarafından sunulmaktadır.", "about.privacy": "Kişisel verilerin gizliliği ilkesi", diff --git a/webapp/channels/src/i18n/uk.json b/webapp/channels/src/i18n/uk.json index 4afba9192e..a0195952b3 100644 --- a/webapp/channels/src/i18n/uk.json +++ b/webapp/channels/src/i18n/uk.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "Enterprise Edition", "about.hash": "Хеш збірки:", "about.hashee": "Хеш збірки EE:", - "about.hashwebapp": "Хеш збірки Webapp:", "about.licensed": "Ліцензовано на:", "about.notice": "Mattermost це стало можливим за допомогою програмного забезпечення з відкритим кодом, яке використовується на нашому сервері , desktop та mobile додатків.", "about.privacy": "Політика конфіденційності", diff --git a/webapp/channels/src/i18n/zh-CN.json b/webapp/channels/src/i18n/zh-CN.json index 2db89a3255..ce73e0e2ff 100644 --- a/webapp/channels/src/i18n/zh-CN.json +++ b/webapp/channels/src/i18n/zh-CN.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "企业版", "about.hash": "编译哈希:", "about.hashee": "企业版编译哈希:", - "about.hashwebapp": "网页应用编译哈系:", "about.licensed": "授权给:", "about.notice": "开源软件帮助 Mattermost 实现了我们的服务端桌面以及移动应用。", "about.privacy": "隐私政策", diff --git a/webapp/channels/src/i18n/zh-TW.json b/webapp/channels/src/i18n/zh-TW.json index 63c968580a..3d61e2d5b0 100644 --- a/webapp/channels/src/i18n/zh-TW.json +++ b/webapp/channels/src/i18n/zh-TW.json @@ -11,7 +11,6 @@ "about.enterpriseEditione1": "企業版", "about.hash": "編譯 Hash:", "about.hashee": "企業版編譯 Hash:", - "about.hashwebapp": "網頁程式建置雜湊:", "about.licensed": "授權給:", "about.notice": "藉由在伺服器桌面行動裝置上使用的開源軟體,才得以實現 Mattermost。", "about.privacy": "隱私政策", From 3ae78cfd952b1ba7783513dc7d7e27df47ce33ce Mon Sep 17 00:00:00 2001 From: master7 Date: Tue, 4 Apr 2023 09:37:18 +0200 Subject: [PATCH 24/58] Translated using Weblate (Polish) Currently translated at 100.0% (5754 of 5754 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/pl/ Translated using Weblate (Polish) Currently translated at 100.0% (5750 of 5750 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/pl/ Translated using Weblate (Polish) Currently translated at 100.0% (2533 of 2533 strings) Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/pl/ --- server/i18n/pl.json | 192 +++++++++++++++++++++++++++++++ webapp/channels/src/i18n/pl.json | 11 +- 2 files changed, 200 insertions(+), 3 deletions(-) diff --git a/server/i18n/pl.json b/server/i18n/pl.json index 25a16ea5db..abf9d3be2d 100644 --- a/server/i18n/pl.json +++ b/server/i18n/pl.json @@ -9862,5 +9862,197 @@ { "id": "app.command.execute.error", "translation": "Nie można wykonać polecenia." + }, + { + "id": "app.user.digest.runs_in_progress.zero_in_progress", + "translation": "Obecnie masz 0 uruchomień w trakcie." + }, + { + "id": "app.user.digest.tasks.all_tasks_command", + "translation": "Użyj `/playbook todo`, aby zobaczyć wszystkie swoje zadania." + }, + { + "id": "app.user.digest.tasks.heading", + "translation": "Twoje przydzielone zadania" + }, + { + "id": "app.user.digest.tasks.zero_assigned", + "translation": "Masz 0 przydzielonych zadań." + }, + { + "id": "app.user.new_run.run_name", + "translation": "Nazwa uruchomienia" + }, + { + "id": "app.user.new_run.title", + "translation": "Uruchom playbook" + }, + { + "id": "app.user.run.add_checklist_item.description", + "translation": "Opis" + }, + { + "id": "app.user.run.add_checklist_item.name", + "translation": "Nazwa" + }, + { + "id": "app.user.run.add_checklist_item.submit_label", + "translation": "Dodaj zadanie" + }, + { + "id": "app.user.run.add_checklist_item.title", + "translation": "Dodaj nowe zadanie" + }, + { + "id": "app.user.run.add_to_timeline.playbook_run", + "translation": "Uruchomienie Playbooka" + }, + { + "id": "app.user.run.add_to_timeline.submit_label", + "translation": "Dodaj do osi czasu uruchomienia" + }, + { + "id": "app.user.run.add_to_timeline.summary", + "translation": "Podsumowanie" + }, + { + "id": "app.user.run.add_to_timeline.summary.help", + "translation": "Maksymalnie 64 znaki" + }, + { + "id": "app.user.run.add_to_timeline.summary.placeholder", + "translation": "Krótkie podsumowanie widoczne na osi czasu" + }, + { + "id": "app.user.run.update_status.finish_run", + "translation": "Zakończ uruchomienie" + }, + { + "id": "app.user.run.update_status.finish_run.placeholder", + "translation": "Oznacz również uruchomienie jako zakończone" + }, + { + "id": "app.user.run.update_status.reminder_for_next_update", + "translation": "Przypomnienie o następnej aktualizacji" + }, + { + "id": "app.user.run.update_status.submit_label", + "translation": "Status aktualizacji" + }, + { + "id": "app.user.digest.runs_in_progress.num_in_progress", + "translation": { + "few": "Masz {{.Count}} uruchomienia w toku:", + "many": "Masz {{.Count}} uruchomień w toku:", + "one": "Masz {{.Count}} uruchomienie w toku:" + } + }, + { + "id": "app.user.digest.tasks.due_in_x_days", + "translation": { + "few": "Termin płatności za {{.Count}} dni", + "many": "Termin płatności za {{.Count}} dni", + "one": "Termin płatności za {{.Count}} dzień" + } + }, + { + "id": "app.user.digest.tasks.due_after_today", + "translation": { + "few": "Masz **{{.Count}} przydzielone zadania, których termin wykonania wypada po dzisiejszym dniu**.", + "many": "Masz **{{.Count}} przydzielonych zadań, których termin wykonania wypada po dzisiejszym dniu**.", + "one": "Masz **{{.Count}} przydzielone zadanie, którego termin wykonania wypada po dzisiejszym dniu**." + } + }, + { + "id": "app.user.digest.tasks.due_today", + "translation": "Do zapłaty dzisiaj" + }, + { + "id": "app.user.digest.tasks.due_x_days_ago", + "translation": "Termin {{.Count}} dni temu" + }, + { + "id": "app.user.digest.tasks.num_assigned", + "translation": { + "few": "Masz {{.Count}} przydzielone zadania:", + "many": "Masz {{.Count}} przydzielonych zadań:", + "one": "Masz {{.Count}} przydzielone zadanie:" + } + }, + { + "id": "app.user.digest.tasks.num_assigned_due_until_today", + "translation": { + "few": "Masz {{.Count}} przydzielone zadania, których termin wykonania właśnie upływa:", + "many": "Masz {{.Count}} przydzielonych zadań, których termin wykonania właśnie upływa:", + "one": "Masz {{.Count}} przydzielone zadanie, którego termin wykonania właśnie upływa:" + } + }, + { + "id": "app.user.new_run.intro", + "translation": "**Właściciel** {{.Username}}" + }, + { + "id": "app.user.new_run.playbook", + "translation": "Playbook" + }, + { + "id": "app.user.new_run.submit_label", + "translation": "Rozpocznij uruchomienie" + }, + { + "id": "app.user.run.confirm_finish.num_outstanding", + "translation": { + "few": "Są **{.Count}} zaległe zadania**. Czy na pewno chcesz zakończyć uruchomienie *{.RunName}}* dla wszystkich uczestników?", + "many": "Jest **{.Count}} zaległych zadań**. Czy na pewno chcesz zakończyć uruchomienie *{.RunName}}* dla wszystkich uczestników?", + "one": "Jest **{.Count}} zaległe zadanie**. Czy na pewno chcesz zakończyć uruchomienie *{.RunName}}* dla wszystkich uczestników?" + } + }, + { + "id": "app.user.run.update_status.num_channel", + "translation": { + "few": "Przedstaw aktualizację dla interesariuszy. Ten post będzie transmitowany na {{.Count}} kanałach.", + "many": "Przedstaw aktualizację dla interesariuszy. Ten post będzie transmitowany na {{.Count}} kanałach.", + "one": "Przedstaw aktualizację dla interesariuszy. Ten post będzie transmitowany na {{.Count}} kanale." + } + }, + { + "id": "app.user.run.update_status.title", + "translation": "Aktualizacje statusu" + }, + { + "id": "app.user.digest.tasks.due_yesterday", + "translation": "Termin na wczoraj" + }, + { + "id": "app.user.run.status_disable", + "translation": "@{.Username}} wyłączył aktualizacje statusu dla [{{.RunName}}]({{.RunURL}})" + }, + { + "id": "app.user.run.status_enable", + "translation": "@{.Username}} włączył aktualizacje statusu dla [{{.RunName}}]({{.RunURL}})" + }, + { + "id": "app.user.run.update_status.change_since_last_update", + "translation": "Zmiana od ostatniej aktualizacji" + }, + { + "id": "app.user.run.confirm_finish.submit_label", + "translation": "Zakończ uruchomienie" + }, + { + "id": "app.user.run.confirm_finish.title", + "translation": "Potwierdź zakończenie uruchomienia" + }, + { + "id": "app.user.run.request_join_channel", + "translation": "@{{.Name}} jest uczestnikiem uruchomienia i chce dołączyć do tego kanału. Każdy członek kanału może go zaprosić.\n" + }, + { + "id": "app.user.run.request_update", + "translation": "@here - @{.Name}} zażądał aktualizacji statusu dla [{{.RunName}}]({{.RunURL}}). \n" + }, + { + "id": "app.user.run.add_to_timeline.title", + "translation": "Dodaj do osi czasu uruchomienia" } ] diff --git a/webapp/channels/src/i18n/pl.json b/webapp/channels/src/i18n/pl.json index 7d3903cd73..f635806dba 100644 --- a/webapp/channels/src/i18n/pl.json +++ b/webapp/channels/src/i18n/pl.json @@ -2648,6 +2648,7 @@ "app.channel.post_update_channel_purpose_message.updated_from": "{username} zaktualizował cel kanału z: {old} na: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} zaktualizował cel kanału na: {new}", "app.plugin.marketplace_plugins.app_error": "Błąd podczas łączenia z serwerem marketplace. Sprawdź ustawienia w [Konsoli systemowej] ({siteURL}/admin_console/plugins/plugin_management).", + "app_bar.marketplace": "Sklep z Aplikacjami", "apps.error": "Błąd: {error}", "apps.error.command.field_missing": "Brakujące wymagane pola: `{fieldName}`.", "apps.error.command.same_channel": "Kanał powtórzony dla pola `{fieldName}`: `{option}`.", @@ -4155,9 +4156,10 @@ "modal.manual_status.title_offline": "Twój status został ustawiony na \"Offline\"", "modal.manual_status.title_ooo": "Twój status został ustawiony na \"Poza biurem\"", "more.details": "Więcej informacji", - "more_channels.count_zero": "0 Wyników", "more_channels.create": "Stwórz kanał", - "more_channels.joined": "Dołączył", + "more_channels.createClick": "Kliknij przycisk 'Utwórz nowy kanał', aby dodać nowy", + "more_channels.join": "Dołącz", + "more_channels.joining": "Dołączanie...", "more_channels.next": "Dalej", "more_channels.noMore": "Brak wyników dla \"{text}\"", "more_channels.prev": "Wstecz", @@ -4225,7 +4227,7 @@ "navbar_dropdown.logout": "Wylogowanie", "navbar_dropdown.manageGroups": "Zarządzaj grupami", "navbar_dropdown.manageMembers": "Zarządzaj użytkownikami", - "navbar_dropdown.marketplace": "Sklep", + "navbar_dropdown.marketplace": "Sklep z Aplikacjami", "navbar_dropdown.menuAriaLabel": "menu główne", "navbar_dropdown.nativeApps": "Pobierz aplikacje", "navbar_dropdown.profileSettings": "Profil", @@ -4872,6 +4874,8 @@ "sidebar.types.favorites": "ULUBIONE", "sidebar.types.unreads": "NIEPRZECZYTANE", "sidebar.unreads": "Więcej nieprzeczytanych", + "sidebar_left.addChannelsCta": "Dodaj kanały", + "sidebar_left.add_channel_cta_dropdown.dropdownAriaLabel": "Dodaj Menu Rozwijane Kanału", "sidebar_left.add_channel_dropdown.browseChannels": "Przeglądaj Kanały", "sidebar_left.add_channel_dropdown.browseOrCreateChannels": "Przeglądaj lub twórz kanały", "sidebar_left.add_channel_dropdown.createCategory": "Utwórz nową kategorię", @@ -4920,6 +4924,7 @@ "sidebar_left.sidebar_channel_menu.unfavoriteChannel": "Cofnij ulubione", "sidebar_left.sidebar_channel_menu.unmuteChannel": "Wyłącz Wyciszenie Kanału", "sidebar_left.sidebar_channel_menu.unmuteConversation": "Wyłącz Wyciszenie Rozmowy", + "sidebar_left.sidebar_channel_navigator.addChannelsCta": "Dodaj kanały", "sidebar_left.sidebar_channel_navigator.inviteUsers": "Zaproś Użytkowników", "sidebar_right_menu.console": "Konsola systemu", "sidebar_right_menu.flagged": "Oznaczone Wiadmości", From 46b14310c0c45a53fdaadfcac70e805a55767493 Mon Sep 17 00:00:00 2001 From: jprusch Date: Tue, 4 Apr 2023 09:37:19 +0200 Subject: [PATCH 25/58] Translated using Weblate (German) Currently translated at 100.0% (5766 of 5766 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/de/ Translated using Weblate (German) Currently translated at 100.0% (2532 of 2532 strings) Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/de/ Translated using Weblate (German) Currently translated at 100.0% (5766 of 5766 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/de/ Translated using Weblate (German) Currently translated at 100.0% (2534 of 2534 strings) Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/de/ Translated using Weblate (German) Currently translated at 100.0% (5754 of 5754 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/de/ Translated using Weblate (German) Currently translated at 100.0% (5754 of 5754 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/de/ Translated using Weblate (German) Currently translated at 100.0% (5751 of 5751 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/de/ Translated using Weblate (German) Currently translated at 100.0% (5750 of 5750 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/de/ --- server/i18n/de.json | 124 ++++++++++++++++++++++++++++++- webapp/channels/src/i18n/de.json | 38 ++++++++-- 2 files changed, 152 insertions(+), 10 deletions(-) diff --git a/server/i18n/de.json b/server/i18n/de.json index 8960847caf..4a855acfb4 100644 --- a/server/i18n/de.json +++ b/server/i18n/de.json @@ -9612,7 +9612,7 @@ }, { "id": "worktemplate.category.product_teams", - "translation": "Produkt-Teams" + "translation": "Produkt" }, { "id": "model.draft.is_valid.priority.app_error", @@ -9628,7 +9628,7 @@ }, { "id": "worktemplate.product_teams.feature_release.description.integration", - "translation": "Steigere die Produktivität in deinem Kanal durch die Integration eines Jira-Bots und eines Github-Bots. Diese werden für dich heruntergeladen." + "translation": "Steigere die Produktivität in deinem Kanal durch die Integration deiner am meistern verwendeten Tools, wie GitHub oder Jira. Diese werden für dich heruntergeladen." }, { "id": "api.templates.cloud_welcome_email.yearly_plan_button", @@ -10049,5 +10049,125 @@ { "id": "app.command.execute.error", "translation": "Kann Befehl nicht ausführen." + }, + { + "id": "api.license.request-trial.bad-request.business-email", + "translation": "Ungültige geschäftliche E-Mail für den Test" + }, + { + "id": "worktemplate.product_teams.sprint_planning.integration", + "translation": "Steigere die Produktivität deines Kanals, indem du die am häufigsten verwendeten Tools wie z. B. Zoom integrierst. Diese werden für dich heruntergeladen." + }, + { + "id": "worktemplate.product_teams.sprint_planning.channel", + "translation": "Chatte mit deinem Team in einem Kanal, der sich leicht mit deinen Boards und Integrationen verbinden lässt." + }, + { + "id": "worktemplate.product_teams.sprint_planning.board", + "translation": "Verfolge den Fortschritt deines Teams bei der Erreichung der wöchentlichen Ziele mit Sprintaufteilung, Priorisierung, Zuweisung von Verantwortlichen und Kommentaren." + }, + { + "id": "worktemplate.product_teams.product_roadmap.channel", + "translation": "Chatte mit deinem Team über das Feedback deiner Kunden, setze Prioritäten und stimmt euch gemeinsam über den Fortschritt ab." + }, + { + "id": "worktemplate.product_teams.product_roadmap.board", + "translation": "Verwende das Produkt-Roadmap-Board, um Benutzer-Feedback zu verwalten, Ressourcen zuzuweisen, Ergebnisse in einer Kalenderansicht anzuzeigen und Probleme nach Priorität zu ordnen." + }, + { + "id": "worktemplate.product_teams.goals_and_okrs.integration", + "translation": "Steigere die Produktivität in deinem Kanal, indem du die am häufigsten verwendeten Tools wie Zoom integrierst, um die Zusammenarbeit zu erleichtern. Diese werden für dich heruntergeladen." + }, + { + "id": "worktemplate.product_teams.goals_and_okrs.channel", + "translation": "Chatte mit deinem Team über Ziele und Fortschritte, asynchron oder in Echtzeit, und bleibe über Änderungen in einem einzigen Kanal auf dem Laufenden." + }, + { + "id": "worktemplate.product_teams.goals_and_okrs.board", + "translation": "Verfolge den Fortschritt deines Teams auf dem Weg zu den Unternehmenszielen mit dem Ziele und OKR Board. Halten Besprechungen mit der Besprechungsagenda auf Kurs." + }, + { + "id": "worktemplate.product_teams.feature_release.description.playbook", + "translation": "Fördere die funktionsübergreifende Zusammenarbeit im Team mit Aufgaben-Checklisten und Automatisierungen, die deinen Entwicklungsprozess unterstützen. Führe anschließend eine Retrospektive durch und nimm Verbesserungen für deine nächste Version vor." + }, + { + "id": "worktemplate.product_teams.feature_release.description.channel", + "translation": "Chatte mit deinem Team über alle Release-Blocker und Änderungen in einem Kanal, der sich leicht mit deinen Boards, Playbooks und anderen Integrationen verbinden lässt." + }, + { + "id": "worktemplate.product_teams.feature_release.description.board", + "translation": "Halte Besprechungen mit der Besprechungsagenda auf dem Laufenden. Verwalte dein Arbeitspensum mit dem Projektaufgabenboard." + }, + { + "id": "worktemplate.product_teams.bug_bash.playbook", + "translation": "Verwende Checklisten, um Testbereiche zuzuweisen, und automatisierte Aufgaben, um einen umfassenden Fehlerbehebungsprozess durchzuführen. Nutze eine Retrospektive, um deinen Prozess zu überprüfen und ihn für das nächste Mal zu verbessern." + }, + { + "id": "worktemplate.product_teams.bug_bash.integration", + "translation": "Steigere die Produktivität in deinem Kanal, indem du die am häufigsten verwendeten Tools, wie z. B. Jira, integrierst, um den Fortschritt bei der Fehlerbehebung zu verfolgen. Diese werden für dich heruntergeladen." + }, + { + "id": "worktemplate.product_teams.bug_bash.channel", + "translation": "Plane und verwalte Fehlerberichte und -behebungen in einem einzigen Kanal, der für dein Team und deine Organisation leicht zugänglich ist." + }, + { + "id": "worktemplate.leadership.goals_and_okrs.integration", + "translation": "Steigere die Produktivität in deinem Kanal, indem du die am häufigsten verwendeten Tools wie Zoom integrierst, um die Zusammenarbeit zu erleichtern. Diese werden für dich heruntergeladen." + }, + { + "id": "worktemplate.leadership.goals_and_okrs.channel", + "translation": "Chatte mit deinem Team über Ziele und Fortschritte, asynchron oder in Echtzeit, und bleibe über Änderungen in einem einzigen Kanal auf dem Laufenden." + }, + { + "id": "worktemplate.leadership.goals_and_okrs.board", + "translation": "Verfolge den Fortschritt deines Teams auf dem Weg zu den Unternehmenszielen mit dem Ziele und OKR Board. Halten Besprechungen mit der Besprechungsagenda auf Kurs." + }, + { + "id": "worktemplate.devops.product_release.playbook", + "translation": "Erstelle wiederholbare Arbeitsabläufe, die einfach zu befolgen und zu implementieren sind, damit die Produktveröffentlichungen zuverlässig und pünktlich erfolgen." + }, + { + "id": "worktemplate.devops.product_release.channel", + "translation": "Chatte einfach und schnell mit deinem Team über tägliche Meilensteine, eventuelle Hindernisse und Änderungen an den zu erbringenden Leistungen." + }, + { + "id": "worktemplate.devops.product_release.board", + "translation": "Verwende das Product Release Board, um den Zeitrahmen und den Prozess für die Freigabe zu unterstützen und sicherzustellen, dass jeder weiß, welche Aufgaben fällig sind." + }, + { + "id": "worktemplate.devops.incident_resolution.description.playbook", + "translation": "Nutze Checklisten und Automatisierungen, um wichtige Teammitglieder einzubeziehen, und teile mit, wie der Vorfall gelöst wird." + }, + { + "id": "worktemplate.devops.incident_resolution.description.channel", + "translation": "Chatte mit deinem Team über Prioritäten, füge Beteiligte hinzu, liefere Updates und arbeite an einer Lösung in einem einzigen Kanal." + }, + { + "id": "worktemplate.devops.incident_resolution.description.board", + "translation": "Verwende das Incident Resolution Board, um wiederholbare Prozesse zu unterstützen und definierte Aufgaben im Team zuzuweisen." + }, + { + "id": "worktemplate.companywide.goals_and_okrs.integration", + "translation": "Steigere die Produktivität in deinem Kanal, indem du die am häufigsten verwendeten Tools wie Zoom integrierst, um die Zusammenarbeit zu erleichtern. Diese werden für dich heruntergeladen." + }, + { + "id": "worktemplate.companywide.goals_and_okrs.channel", + "translation": "Chatte mit deinem Team über Ziele und Fortschritte, asynchron oder in Echtzeit, und bleibe über Änderungen in einem einzigen Kanal auf dem Laufenden." + }, + { + "id": "worktemplate.companywide.goals_and_okrs.board", + "translation": "Verfolge den Fortschritt deines Teams auf dem Weg zu den Unternehmenszielen mit dem Ziele und OKR Board. Halten Besprechungen mit der Besprechungsagenda auf Kurs." + }, + { + "id": "worktemplate.companywide.create_project.integration", + "translation": "Steigere die Produktivität deines Kanals durch die Integration am deiner am häufigsten verwendeten Tools. Diese werden für dich heruntergeladen." + }, + { + "id": "worktemplate.companywide.create_project.channel", + "translation": "Chatte mit deinem Team über ein neues Projekt und entscheide, wie es strukturiert werden soll, und zwar in einem Kanal zur Zusammenarbeit." + }, + { + "id": "worktemplate.companywide.create_project.board", + "translation": "Verwend eine Kanban-Board, um deine Projektaufgaben und -fortschritte zu definieren und zu verfolgen." } ] diff --git a/webapp/channels/src/i18n/de.json b/webapp/channels/src/i18n/de.json index cabaa6ab80..847c1455d7 100644 --- a/webapp/channels/src/i18n/de.json +++ b/webapp/channels/src/i18n/de.json @@ -1337,8 +1337,9 @@ "admin.license.renewalCard.reviewNumbers": "Überprüfe deine Zahlen unten, um sicherzustellen, dass du für die richtige Anzahl von Benutzern erneuerst.", "admin.license.renewalCard.usersNumbers": "**Aktive Benutzer:** {activeUsersNum}", "admin.license.title": "Edition und Lizenz", - "admin.license.trial-request.accept-terms": "Indem ich auf Starte Testl klicke, stimme ich dem Mattermost Software und Services License Agreement, Datenschutz-Richtlinien und dem Erhalt von Produkt-E-Mails zu.", + "admin.license.trial-request.accept-terms": "Indem ich auf Starte Test klicke, stimme ich dem Mattermost Software und Services License Agreement, Datenschutz-Richtlinien und dem Erhalt von Produkt-E-Mails zu.", "admin.license.trial-request.embargoed": "Wir konnten die Anfrage auf Grund von Embargo-Beschränkungen für bestimmte Länder nicht verarbeiten. Lerne mehr in unserer Dokumentation, oder kontaktiere legal@mattermost.com für Fragen rund um Exportbeschränkungen.", + "admin.license.trial-request.embargoed.button": "Schliessen", "admin.license.trial-request.startTrial": "Starte Test", "admin.license.trial-request.title": "Teste Mattermost Enterprise Edition kostenlos für die nächsten 30 Tage. Keine Kaufverpflichtung oder Kreditkarte erforderlich. ", "admin.license.trialCard.contactSales": "Vertrieb kontaktieren", @@ -2562,6 +2563,9 @@ "admin.webserverModeUncompressed": "Unkomprimiert", "admin.webserverModeUncompressedDescription": "Der Mattermost-Server wird statische Dateien unkomprimiert bereitstellen.", "admin_settings.save_unsaved_changes": "Bitte speichere ungespeicherte Änderungen zuerst", + "air_gapped_modal.close": "Schliessen", + "air_gapped_modal.description": "Um deinen Test zu starten, besuche bitte {link} und fordere einen Testschlüssel an.", + "air_gapped_modal.title": "Testschlüssel anfordern", "alert_banner.tooltipCloseBtn": "Schliessen", "analytics.chart.loading": "Lade...", "analytics.chart.meaningful": "Nicht genügend Daten für eine aussagekräftige Darstellung.", @@ -2648,6 +2652,7 @@ "app.channel.post_update_channel_purpose_message.updated_from": "{username} hat den Kanalzweck aktualisiert von: {old} auf: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} hat den Kanalzweck geändert zu: {new}", "app.plugin.marketplace_plugins.app_error": "Fehler beim Verbinden mit dem Marktplatz-Server. Bitte überprüfe deine Einstellungen in der [Systemkonsole]({siteURL}/admin_console/plugins/plugin_management).", + "app_bar.marketplace": "App-Marktplatz", "apps.error": "Fehler: {error}", "apps.error.command.field_missing": "Erforderliche Felder fehlen: `{fieldName}`.", "apps.error.command.same_channel": "Kanal wiederholt für Feld `{fieldName}`: `{option}`.", @@ -4155,9 +4160,10 @@ "modal.manual_status.title_offline": "Dein Status wurde auf \"Offline\" gesetzt", "modal.manual_status.title_ooo": "Dein Status ist auf \"Nicht im Büro\" gesetzt", "more.details": "Mehr Details", - "more_channels.count_zero": "Keine Ergebnisse", "more_channels.create": "Kanal erstellen", - "more_channels.joined": "Verknüpft", + "more_channels.createClick": "Klicke auf 'Neuen Kanal erstellen' um einen Neuen zu erzeugen", + "more_channels.join": "Beitreten", + "more_channels.joining": "Beitreten...", "more_channels.next": "Weiter", "more_channels.noMore": "Keine Ergebnisse für \"{text}\"", "more_channels.prev": "Zurück", @@ -4225,7 +4231,7 @@ "navbar_dropdown.logout": "Abmelden", "navbar_dropdown.manageGroups": "Gruppen verwalten", "navbar_dropdown.manageMembers": "Mitglieder verwalten", - "navbar_dropdown.marketplace": "Plugin-Marktplatz", + "navbar_dropdown.marketplace": "App-Marktplatz", "navbar_dropdown.menuAriaLabel": "Hauptmenü", "navbar_dropdown.nativeApps": "Apps herunterladen", "navbar_dropdown.profileSettings": "Profil", @@ -4283,9 +4289,10 @@ "onboardingTask.checklist.downloads": "Jetzt, da du alles konfiguriert hast, lade unsere Apps runter.", "onboardingTask.checklist.higher_security_features": "Interessiert an unseren Hochsicherheitsfunktionen?", "onboardingTask.checklist.main_subtitle": "Legen wir los.", + "onboardingTask.checklist.no_tanks": "Nein, danke", "onboardingTask.checklist.start_enterprise_now": "Starte jetzt Deinen kostenfreien Enterprise-Test!", "onboardingTask.checklist.task_complete_your_profile": "Vervollständige dein Profil.", - "onboardingTask.checklist.task_create_from_work_template": "Erstellen mit einer Vorlage - richte einen Kanal mit verknüpften Boards und Playbooks ein.", + "onboardingTask.checklist.task_create_from_work_template": "Erstellen aus einer Vorlage", "onboardingTask.checklist.task_download_mm_apps": "Lade die Desktop-, Tablet- und Handy-Apps runter.", "onboardingTask.checklist.task_explore_other_tools_in_platform": "Erkunde andere Tools auf der Plattform.", "onboardingTask.checklist.task_invite_team_members": "Lade Teammitglieder in den Arbeitsbereich ein.", @@ -4857,7 +4864,7 @@ "sidebar.directchannel.you": "{displayname} (Sie)", "sidebar.menu.item.notSelected": "nicht ausgewählt", "sidebar.menu.item.selected": "ausgewählt", - "sidebar.openDirectMessage": "Direktnachricht senden", + "sidebar.openDirectMessage": "Direktnachricht öffnen", "sidebar.show": "Anzeigen", "sidebar.sort": "Sortierung", "sidebar.sortedByRecencyLabel": "Letzte Aktivität", @@ -4872,6 +4879,8 @@ "sidebar.types.favorites": "FAVORITEN", "sidebar.types.unreads": "UNGELESENE", "sidebar.unreads": "Weitere Ungelesene", + "sidebar_left.addChannelsCta": "Kanäle hinzufügen", + "sidebar_left.add_channel_cta_dropdown.dropdownAriaLabel": "Kanal-Dropdown hinzufügen", "sidebar_left.add_channel_dropdown.browseChannels": "Kanäle durchsuchen", "sidebar_left.add_channel_dropdown.browseOrCreateChannels": "Kanäle erstellen oder durchsuchen", "sidebar_left.add_channel_dropdown.createCategory": "Neue Kategorie erstellen", @@ -4880,7 +4889,7 @@ "sidebar_left.add_channel_dropdown.invitePeople": "Personen einladen", "sidebar_left.add_channel_dropdown.invitePeopleExtraText": "Personen zum Team hinzufügen", "sidebar_left.add_channel_dropdown.work_template": "Aus einer Vorlage erstellen", - "sidebar_left.add_channel_dropdown.work_template_extra": "Richte einen Kanal mit verknüpften Boards und Playbooks ein", + "sidebar_left.add_channel_dropdown.work_template_extra": "Verknüpfe Kanäle, Boards und Playbooks miteinander", "sidebar_left.channel_filter.filterByUnread": "Gefiltert durch ungelesen", "sidebar_left.channel_filter.filterUnreadAria": "Ungelesen Filter", "sidebar_left.channel_filter.showAllChannels": "Alle Kanäle anzeigen", @@ -4920,6 +4929,7 @@ "sidebar_left.sidebar_channel_menu.unfavoriteChannel": "Nicht favorisieren", "sidebar_left.sidebar_channel_menu.unmuteChannel": "Stummschaltung aufheben", "sidebar_left.sidebar_channel_menu.unmuteConversation": "Stummschaltung aufheben", + "sidebar_left.sidebar_channel_navigator.addChannelsCta": "Kanäle hinzufügen", "sidebar_left.sidebar_channel_navigator.inviteUsers": "Benutzer einladen", "sidebar_right_menu.console": "Systemkonsole", "sidebar_right_menu.flagged": "Markierte Nachrichten", @@ -4975,6 +4985,18 @@ "start_trial.modal_title": "Starte jetzt deine kostenlose Enterprise-Testversion", "start_trial.tutorialTip.desc": "Probiere unsere am meisten gefragten Premium Funktionen: Lege den Benutzerzugriff mit Gast-Konten fest, automatisiere Compliance Berichte und sende sichere, mobile Nur-ID Push-Nachrichten.", "start_trial.tutorialTip.title": "Teste kostenfrei Premium Funktionen", + "start_trial_form.company_name": "Firmenname", + "start_trial_form.company_size": "Größe des Unternehmens", + "start_trial_form.disclaimer": "Mit Auswählen von Starte Test, stimme ich dem Mattermost Software Evaluation Agreement und der Datenschutzrichtlinie zu, und erhalte Produktemails.", + "start_trial_form.email": "Geschäftliche E-Mail", + "start_trial_form.invalid_business_email": "Bitte gib eine gültige geschäftliche E-Mail-Adresse ein.", + "start_trial_form.modal_body": "Nur ein paar kurze Hinweise, die uns helfen, deine Testerfahrung individuell zu gestalten", + "start_trial_form.modal_btn.start": "Test starten", + "start_trial_form.modal_title": "Test starten", + "start_trial_form.name": "Name", + "start_trial_form_modal.failureModal.subtitle": "Es gab ein Problem bei der Bearbeitung deiner Testanfrage.", + "start_trial_form_modal.failureModal.subtitle2": "Bitte versuche es erneut oder kontaktiere den Support.", + "start_trial_form_modal.failureModal.title": "Bitte versuche es erneut", "status_dropdown.dnd_sub_menu_header": "Benachrichtigungen ausschalten bis:", "status_dropdown.dnd_sub_menu_item.custom": "Benutzerdefiniert", "status_dropdown.dnd_sub_menu_item.one_hour": "Eine Stunde", @@ -5676,7 +5698,7 @@ "work_templates.customize.name_label_channels_playbooks": "Benenne deinen Kanal und Playbook", "work_templates.customize.private_playbook_license_issue": "Für private Playbooks ist eine Enterprise-Lizenz erforderlich.", "work_templates.customize.visibility_title": "Wer soll Zugang dazu haben?", - "work_templates.menu.modal_title": "Beginne mit einer Vorlage", + "work_templates.menu.modal_title": "Erstellen aus einer Vorlage", "work_templates.menu.quick_use": "Schneller Einsatz", "work_templates.menu.template_title": "VORLAGE", "work_templates.menu.usecase_boards_count": "{boardsCount, plural, =1 {# Board} other {# Boards}}", From c8ae62cb1ed9ec14561fdbbb2c3a2305974173e8 Mon Sep 17 00:00:00 2001 From: Pierre JENICOT Date: Tue, 4 Apr 2023 09:37:20 +0200 Subject: [PATCH 26/58] Translated using Weblate (French) Currently translated at 85.0% (4889 of 5750 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/fr/ --- webapp/channels/src/i18n/fr.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/webapp/channels/src/i18n/fr.json b/webapp/channels/src/i18n/fr.json index bc8beb3640..77d9b1a797 100644 --- a/webapp/channels/src/i18n/fr.json +++ b/webapp/channels/src/i18n/fr.json @@ -4470,7 +4470,13 @@ "user.settings.advance.sendDesc.mac": "Si activé, ⌘ + ENTRÉE envoie le message et ENTRÉE insère une nouvelle ligne.", "user.settings.advance.sendTitle": "Envoi des messages avec CTRL+ENTRÉE", "user.settings.advance.sendTitle.mac": "Envoi des messages avec ⌘+ENTRÉE", + "user.settings.advance.startFromLeftOff": "Reprendre là où je m'étais arrêté", + "user.settings.advance.startFromNewest": "Commencez par le message le plus récent", + "user.settings.advance.syncDrafts.Desc": "Lorsqu'ils sont activés, les brouillons de messages sont synchronisés avec le serveur afin qu'ils soient accessibles depuis n'importe quel appareil. Lorsqu'ils sont désactivés, les brouillons de message ne sont enregistrés que localement sur l'appareil sur lequel ils sont rédigés.", + "user.settings.advance.syncDrafts.Title": "Autoriser la synchronisation des messages en brouillon avec le serveur", "user.settings.advance.title": "Paramètres avancés", + "user.settings.advance.unreadScrollPositionDesc": "Choisissez le positionnement lors d'un canal non lu. Les canaux sont toujours marqués comme lus lorsqu'ils sont consultés.", + "user.settings.advance.unreadScrollPositionTitle": "Positionnement lors qu'un canal non lu", "user.settings.custom_theme.awayIndicator": "Indicateur « absent »", "user.settings.custom_theme.buttonBg": "Arrière-plan du bouton", "user.settings.custom_theme.buttonColor": "Texte de bouton", From ca2c77f5569a2d8945473c04433d8252fe1f8fc5 Mon Sep 17 00:00:00 2001 From: MArtin Johnson Date: Tue, 4 Apr 2023 09:37:20 +0200 Subject: [PATCH 27/58] Translated using Weblate (Swedish) Currently translated at 100.0% (5754 of 5754 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/sv/ Translated using Weblate (Swedish) Currently translated at 100.0% (2533 of 2533 strings) Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/sv/ --- server/i18n/sv.json | 208 +++++++++++++++++++++++++++++++ webapp/channels/src/i18n/sv.json | 14 ++- 2 files changed, 219 insertions(+), 3 deletions(-) diff --git a/server/i18n/sv.json b/server/i18n/sv.json index f5a3da2887..03d73e6a12 100644 --- a/server/i18n/sv.json +++ b/server/i18n/sv.json @@ -9837,5 +9837,213 @@ { "id": "app.oauth.remove_auth_data_by_client_id.app_error", "translation": "Kunde inte rensa oauth-information." + }, + { + "id": "app.user.run.update_status.title", + "translation": "Statusuppdatering" + }, + { + "id": "app.user.run.update_status.submit_label", + "translation": "Uppdatera status" + }, + { + "id": "app.user.run.update_status.reminder_for_next_update", + "translation": "Påminnelse om nästa uppdatering" + }, + { + "id": "app.user.run.update_status.num_channel", + "translation": { + "one": "Ge en uppdatering till intressenterna. Detta inlägg kommer att publiceras i {{.Count}} kanal.", + "other": "Ge en uppdatering till intressenterna. Detta inlägg kommer att publiceras i {{.Count}} kanaler." + } + }, + { + "id": "app.user.run.update_status.finish_run.placeholder", + "translation": "Markera även körningen som avslutad" + }, + { + "id": "app.user.run.update_status.finish_run", + "translation": "Slutför körningen" + }, + { + "id": "app.user.run.update_status.change_since_last_update", + "translation": "Förändring sedan den senaste uppdateringen" + }, + { + "id": "app.user.run.status_enable", + "translation": "@{{.Username}} aktiverade statusuppdateringar för [{{.RunName}}]({{.RunURL}})" + }, + { + "id": "app.user.run.status_disable", + "translation": "@{{.Username}} inaktiverade statusuppdateringarna för [{{.RunName}}]({{.RunURL}})" + }, + { + "id": "app.user.run.request_update", + "translation": "@here - @{{.Name}} begärde en statusuppdatering för [{{.RunName}}]({{.RunURL}}). \n" + }, + { + "id": "app.user.run.request_join_channel", + "translation": "@{{.Name}} är en deltagare i en körning och vill gå med i den här kanalen. Alla medlemmar i kanalen kan bjuda in dem.\n" + }, + { + "id": "app.user.run.confirm_finish.title", + "translation": "Bekräfta att avsluta körningen" + }, + { + "id": "app.user.run.confirm_finish.submit_label", + "translation": "Slutför körningen" + }, + { + "id": "app.user.run.confirm_finish.num_outstanding", + "translation": { + "one": "Det finns **{{.Count}} utestående uppgift**. Är du säker på att du vill avsluta körningen *{{.RunName}}* för alla deltagare?", + "other": "Det finns **{{.Count}} utestående uppgifter**. Är du säker på att du vill avsluta körningen *{{.RunName}}* för alla deltagare?" + } + }, + { + "id": "app.user.run.add_to_timeline.title", + "translation": "Lägg till i tidslinjen för körning" + }, + { + "id": "app.user.run.add_to_timeline.summary.placeholder", + "translation": "Kort sammanfattning som visas i tidslinjen" + }, + { + "id": "app.user.run.add_to_timeline.summary.help", + "translation": "Max 64 tecken" + }, + { + "id": "app.user.run.add_to_timeline.summary", + "translation": "Sammanfattning" + }, + { + "id": "app.user.run.add_to_timeline.submit_label", + "translation": "Lägg till i tidslinjen för körning" + }, + { + "id": "app.user.run.add_to_timeline.playbook_run", + "translation": "Kör Playbook" + }, + { + "id": "app.user.run.add_checklist_item.title", + "translation": "Lägg till en ny uppgift" + }, + { + "id": "app.user.run.add_checklist_item.submit_label", + "translation": "Lägg till en uppgift" + }, + { + "id": "app.user.run.add_checklist_item.name", + "translation": "Namn" + }, + { + "id": "app.user.run.add_checklist_item.description", + "translation": "Beskrivning" + }, + { + "id": "app.user.new_run.title", + "translation": "Kör playbook" + }, + { + "id": "app.user.new_run.submit_label", + "translation": "Starta körning" + }, + { + "id": "app.user.new_run.run_name", + "translation": "Namn på körning" + }, + { + "id": "app.user.new_run.playbook", + "translation": "Playbook" + }, + { + "id": "app.user.new_run.intro", + "translation": "**Ägare** {{.Username}}" + }, + { + "id": "app.user.digest.tasks.zero_assigned", + "translation": "Du har 0 tilldelade uppgifter." + }, + { + "id": "app.user.digest.tasks.num_assigned_due_until_today", + "translation": { + "one": "Du har {{.Count}} tilldelad uppgift som nu är förfallen:", + "other": "Du har {{.Count}} tilldelade uppgifter som nu är förfallna:" + } + }, + { + "id": "app.user.digest.tasks.num_assigned", + "translation": { + "one": "Du har {{.Count}} tilldelad uppgift:", + "other": "Du har {{.Count}} tilldelade uppgifter:" + } + }, + { + "id": "app.user.digest.tasks.heading", + "translation": "Dina tilldelade uppgifter" + }, + { + "id": "app.user.digest.tasks.due_yesterday", + "translation": "Skulle utförts igår" + }, + { + "id": "app.user.digest.tasks.due_x_days_ago", + "translation": "Försenad {{.Count}} dagar" + }, + { + "id": "app.user.digest.tasks.due_in_x_days", + "translation": { + "one": "Ska utföras inom {{.Count}} dag", + "other": "Ska utföras inom {{.Count}} dagar" + } + }, + { + "id": "app.user.digest.tasks.due_today", + "translation": "Ska utföras idag" + }, + { + "id": "app.user.digest.tasks.due_after_today", + "translation": { + "one": "Du har **{{.Count}} tilldelad uppgift som ska utföras idag**.", + "other": "Du har **{{.Count}} tilldelade uppgifter som ska utföras idag**." + } + }, + { + "id": "app.user.digest.tasks.all_tasks_command", + "translation": "Använd `/playbook todo` för att se alla dina uppgifter." + }, + { + "id": "app.user.digest.runs_in_progress.zero_in_progress", + "translation": "Du har 0 pågående körningar." + }, + { + "id": "app.user.digest.runs_in_progress.num_in_progress", + "translation": { + "one": "Du har {{.Count}} körning som för närvarande pågår:", + "other": "Du har {{.Count}} körningar som för närvarande pågår:" + } + }, + { + "id": "app.user.digest.runs_in_progress.heading", + "translation": "Körningar som pågår" + }, + { + "id": "app.user.digest.overdue_status_updates.zero_overdue", + "translation": "Du har 0 försenade körningar." + }, + { + "id": "app.user.digest.overdue_status_updates.num_overdue", + "translation": { + "one": "Du har {{.Count}} körning som borde ha fått en statusuppdatering:", + "other": "Du har {{.Count}} körningar som borde ha fått en statusuppdatering:" + } + }, + { + "id": "app.user.digest.overdue_status_updates.heading", + "translation": "Status om förseningar" + }, + { + "id": "app.command.execute.error", + "translation": "Kunde inte utföra kommandot." } ] diff --git a/webapp/channels/src/i18n/sv.json b/webapp/channels/src/i18n/sv.json index a49a740eb4..0bbb1aae3f 100644 --- a/webapp/channels/src/i18n/sv.json +++ b/webapp/channels/src/i18n/sv.json @@ -2126,7 +2126,7 @@ "admin.service.corsExposedHeadersTitle": "CORS Exposed Headers:", "admin.service.corsHeadersEx": "X-My-Header", "admin.service.corsTitle": "Tillåt cross-origin requests från:", - "admin.service.developerDesc": "När aktiverad kommer JavaScript-error visas i ett lilafärgat fält högst upp i användargränssnittet. Detta är inte rekommenderat i en produktionsmiljö. ", + "admin.service.developerDesc": "När aktiverad kommer JavaScript-error visas i ett lilafärgat fält högst upp i användargränssnittet. Detta är inte rekommenderat i en produktionsmiljö.", "admin.service.developerTitle": "Aktivera utvecklarläge: ", "admin.service.disableBotOwnerDeactivatedTitle": "Spärra bot-konton när dess ägare blir avaktiverad:", "admin.service.disableBotWhenOwnerIsDeactivated": "När en användare blir avaktiverad, spärras alla bot-konton som hanteras av användaren. För att aktivera bot-kontot, gå till [Integrations > Bot Accounts]({siteURL}/_redirect/integrations/bots).", @@ -2648,6 +2648,7 @@ "app.channel.post_update_channel_purpose_message.updated_from": "{username} uppdaterat kanal syfte från: {old} till: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} ändrade kanalens rubrik till: {new}", "app.plugin.marketplace_plugins.app_error": "Fel vid anslutning till marketplace server. Kontrollera inställningarna i [System Console]({siteURL}/admin_console/plugins/plugin_management).", + "app_bar.marketplace": "App Marketplace", "apps.error": "Fel: {error}", "apps.error.command.field_missing": "Nödvändiga fält saknas: `{fieldName}`.", "apps.error.command.same_channel": "Kanal upprepas i fältet `{fieldName}`: `{option}`.", @@ -4156,8 +4157,11 @@ "modal.manual_status.title_ooo": "Din status är satt till \"Inte på kontoret\"", "more.details": "Mer information", "more_channels.create": "Skapa kanal", + "more_channels.createClick": "Klicka på 'Skapa ny kanal' för att skapa en ny", + "more_channels.join": "Gå med", + "more_channels.joining": "Går med...", "more_channels.next": "Nästa", - "more_channels.noMore": "Det finns inga fler kanaler att gå med i", + "more_channels.noMore": "Inget resultat för \"{text}\"", "more_channels.prev": "Föregående", "more_channels.show_archived_channels": "Visa: Arkiverade kanaler", "more_channels.show_public_channels": "Publika kanaler", @@ -4223,7 +4227,7 @@ "navbar_dropdown.logout": "Logga ut", "navbar_dropdown.manageGroups": "Hantera grupper", "navbar_dropdown.manageMembers": "Hantera medlemmar", - "navbar_dropdown.marketplace": "Marketplace", + "navbar_dropdown.marketplace": "App Marketplace", "navbar_dropdown.menuAriaLabel": "Huvudmeny", "navbar_dropdown.nativeApps": "Ladda ner app", "navbar_dropdown.profileSettings": "Profil", @@ -4368,6 +4372,7 @@ "payment_form.no_billing_address": "Ingen fakturaadress tillagd", "payment_form.no_credit_card": "Inget betalkort tillagt", "payment_form.saved_payment_method": "Spara betalmetod", + "payment_form.shipping_address": "Leveransadress", "payment_form.zipcode": "ZIP/Postnummer", "pending_post_actions.cancel": "Avbryt", "pending_post_actions.retry": "Försök igen", @@ -4869,6 +4874,8 @@ "sidebar.types.favorites": "FAVORITER", "sidebar.types.unreads": "OLÄSTA", "sidebar.unreads": "Fler olästa meddelanden", + "sidebar_left.addChannelsCta": "Lägg till kanaler", + "sidebar_left.add_channel_cta_dropdown.dropdownAriaLabel": "Lägg till en rullgardinsmeny för kanaler", "sidebar_left.add_channel_dropdown.browseChannels": "Bläddra bland kanalerna", "sidebar_left.add_channel_dropdown.browseOrCreateChannels": "Bläddra eller skapa kanaler", "sidebar_left.add_channel_dropdown.createCategory": "Skapa ny kategori", @@ -4917,6 +4924,7 @@ "sidebar_left.sidebar_channel_menu.unfavoriteChannel": "Ta bort favorit", "sidebar_left.sidebar_channel_menu.unmuteChannel": "Ljud på i kanalen", "sidebar_left.sidebar_channel_menu.unmuteConversation": "Ljud på i konversationen", + "sidebar_left.sidebar_channel_navigator.addChannelsCta": "Lägg till kanaler", "sidebar_left.sidebar_channel_navigator.inviteUsers": "Bjud in användare", "sidebar_right_menu.console": "Systemkonsol", "sidebar_right_menu.flagged": "Markerade meddelanden", From 3f863afbe2f82fe1423b2809ed21fb4affa40664 Mon Sep 17 00:00:00 2001 From: Frank Tang Date: Tue, 4 Apr 2023 09:37:21 +0200 Subject: [PATCH 28/58] Translated using Weblate (Chinese (Simplified)) Currently translated at 80.1% (4620 of 5766 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/zh_Hans/ Translated using Weblate (Chinese (Simplified)) Currently translated at 99.4% (2517 of 2532 strings) Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/zh_Hans/ Translated using Weblate (Chinese (Simplified)) Currently translated at 79.7% (4600 of 5766 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/zh_Hans/ Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (2534 of 2534 strings) Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/zh_Hans/ Translated using Weblate (Chinese (Simplified)) Currently translated at 79.7% (4586 of 5754 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/zh_Hans/ --- server/i18n/zh-CN.json | 66 ++++++++++++++++++++++++++++- webapp/channels/src/i18n/zh-CN.json | 45 +++++++++++++++++++- 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/server/i18n/zh-CN.json b/server/i18n/zh-CN.json index b5bd72476a..5eb04cde8f 100644 --- a/server/i18n/zh-CN.json +++ b/server/i18n/zh-CN.json @@ -9457,7 +9457,7 @@ }, { "id": "worktemplate.category.product_teams", - "translation": "产品团队" + "translation": "产品" }, { "id": "worktemplate.category.leadership", @@ -10030,5 +10030,69 @@ { "id": "api.license.true_up_review.create_error", "translation": "无法创建真实的状态记录" + }, + { + "id": "api.license.request-trial.bad-request.business-email", + "translation": "无效的商务试用邮箱" + }, + { + "id": "worktemplate.product_teams.feature_release.description.integration", + "translation": "通过集成大多您使用过的工具(比如 GitHub)在您的频道里提高生产力,实现你的功能发布。这些工具将为你下载。" + }, + { + "id": "worktemplate.product_teams.feature_release.description.channel", + "translation": "在一个频道与你的团队讨论任何的发布障碍和变动,并很容易的与你的面板,Playbook或者其他的集成功能连接。" + }, + { + "id": "worktemplate.product_teams.feature_release.description.board", + "translation": "使用会议安排面板保持会议一起正常。使用项目任务面板管理你的工作量。" + }, + { + "id": "worktemplate.product_teams.bug_bash.integration", + "translation": "通过集成大多您使用过的工具(比如Jira)在您的频道里提高生产力,跟踪你的Bug解决过程。这些工具将为你下载。" + }, + { + "id": "worktemplate.leadership.goals_and_okrs.integration", + "translation": "通过集成大多您使用过的工具(比如 Zoom)在您的频道里提高生产力,实行更容易的协作。这些工具将为你下载。" + }, + { + "id": "worktemplate.leadership.goals_and_okrs.channel", + "translation": "和您的团队讨论目标和进度,以异步或者同步的方式,在同一个频道中保持跟上任何发生的变化。" + }, + { + "id": "worktemplate.leadership.goals_and_okrs.board", + "translation": "使用目标和OKR面板跟踪您的团队进度向组织目标推进。使用会议安排面板保持会议一起正常。" + }, + { + "id": "worktemplate.devops.incident_resolution.description.channel", + "translation": "在一单独频道与您的团队讨论优先级、添加利益相关者,提供更新,向解决的方向努力。" + }, + { + "id": "worktemplate.devops.incident_resolution.description.board", + "translation": "使用事故解决面板来实现重复性的流程和分配跨越整个团队的任务。" + }, + { + "id": "worktemplate.companywide.goals_and_okrs.integration", + "translation": "通过集成大多您使用过的工具(比如 Zoom)在您的频道里提高生产力,实行更容易的协作。这些工具将为你下载。" + }, + { + "id": "worktemplate.companywide.goals_and_okrs.channel", + "translation": "和您的团队讨论目标和进度,以异步或者同步的方式,在同一个频道中保持跟上任何发生的变化。" + }, + { + "id": "worktemplate.companywide.goals_and_okrs.board", + "translation": "使用目标和OKR面板跟踪您的团队进度向组织目标推进。使用会议安排面板保持会议一起正常。" + }, + { + "id": "worktemplate.companywide.create_project.integration", + "translation": "通过集成大多您使用过的工具在您的频道里提高生产力。这些工具将为你下载。" + }, + { + "id": "worktemplate.companywide.create_project.channel", + "translation": "与您的团队在一个协作频道里讨论新的项目并且决定如何你们将如此组织。" + }, + { + "id": "worktemplate.companywide.create_project.board", + "translation": "使用看板面板定义和跟踪您的项目任务列表和进度。" } ] diff --git a/webapp/channels/src/i18n/zh-CN.json b/webapp/channels/src/i18n/zh-CN.json index ce73e0e2ff..4672c79469 100644 --- a/webapp/channels/src/i18n/zh-CN.json +++ b/webapp/channels/src/i18n/zh-CN.json @@ -318,7 +318,16 @@ "admin.billing.subscription.creditCardExpired": "您的信用卡已过期。请更新您的付款信息,以免造成任何中断。", "admin.billing.subscription.creditCardHasExpired": "您的信用卡已过期", "admin.billing.subscription.creditCardHasExpired.description": "请更新您的 付款信息 以避免任何中断服务。", + "admin.billing.subscription.deleteWorkspaceModal.cancelButton": "保持订阅", + "admin.billing.subscription.deleteWorkspaceModal.deleteButton": "删除工作区", + "admin.billing.subscription.deleteWorkspaceModal.downgradeButton": "降级为免费", + "admin.billing.subscription.deleteWorkspaceModal.title": "您确定要删除吗?", + "admin.billing.subscription.deleteWorkspaceModal.usage": "作为你付费订阅Mattermost {sku} 的一部分,你目前创建了 ", "admin.billing.subscription.deleteWorkspaceModal.usageDetails": "{messageCount} 条消息和 {fileSize} 的文件", + "admin.billing.subscription.deleteWorkspaceModal.warning": "删除您的工作区是决定性的操作。在删除时,您将失去所有相关数据并且没有能力进行恢复。如果您降级到免费版,您将仍然能看到此信息。", + "admin.billing.subscription.deleteWorkspaceSection.delete": "删除工作区", + "admin.billing.subscription.deleteWorkspaceSection.description": "删除 {workspaceLink} 是最终决定并且以后不能恢复。", + "admin.billing.subscription.deleteWorkspaceSection.title": "删除你的工作区", "admin.billing.subscription.downgradedSuccess": "您现在订阅了 {productName}", "admin.billing.subscription.downgrading": "降级您的工作区", "admin.billing.subscription.featuresAvailable": "{productName} 功能现在已可以使用。", @@ -369,6 +378,7 @@ "admin.billing.subscription.planDetails.userCount": "{userCount} 位用户", "admin.billing.subscription.privateCloudCard.cloudEnterprise.description": "在 Mattermost,我们与您和您的团队合作,以满足您对整个产品的需求。如果您正在寻找年度折扣,请联系我们的销售团队。", "admin.billing.subscription.privateCloudCard.cloudEnterprise.title": "在寻找年度折扣吗? ", + "admin.billing.subscription.privateCloudCard.cloudFree.description": "使用访客账户,Office365套件集起,GitLab SSO和高级权限优化你的流程。", "admin.billing.subscription.privateCloudCard.cloudFree.title": "升级至 Cloud Professional 版", "admin.billing.subscription.privateCloudCard.cloudProfessional.description": "拥有高级支持的高级安全性和合规性功能。详细信息请参阅 {pricingLink}。", "admin.billing.subscription.privateCloudCard.cloudProfessional.title": "升级到企业级云", @@ -386,6 +396,7 @@ "admin.billing.subscription.providePaymentDetails": "提供您的付款明细", "admin.billing.subscription.returnToTeam": "返回到{team}", "admin.billing.subscription.stateprovince": "州/省", + "admin.billing.subscription.switchedToAnnual.title": "您现在的切换到了 {selectedProductName}", "admin.billing.subscription.title": "订阅", "admin.billing.subscription.updatePaymentInfo": "更新付款信息", "admin.billing.subscription.upgradedSuccess": "您现在已升级到{productName}", @@ -393,6 +404,8 @@ "admin.billing.subscription.userCount.tooltipTitle": "当前用户数", "admin.billing.subscription.verifyPaymentInformation": "验证您的付款信息中", "admin.billing.subscription.viewBilling": "查看账单", + "admin.billing.subscriptions.billing_summary.explore_enterprise": "浏览企业版功能", + "admin.billing.subscriptions.billing_summary.explore_enterprise.cta": "查看所有功能", "admin.billing.subscriptions.billing_summary.lastInvoice.failed": "失败", "admin.billing.subscriptions.billing_summary.lastInvoice.monthlyFlatFee": "每月固定费用", "admin.billing.subscriptions.billing_summary.lastInvoice.paid": "已支付", @@ -404,11 +417,26 @@ "admin.billing.subscriptions.billing_summary.lastInvoice.total": "总计", "admin.billing.subscriptions.billing_summary.lastInvoice.userCount": " x {users} 用户", "admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial": "{users} 用户", + "admin.billing.subscriptions.billing_summary.lastInvoice.viewInvoice": "查看发票", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges": "什么是部分费用?", "admin.billing.subscriptions.billing_summary.lastInvoice.whatArePartialCharges.message": "在一个月的整个时间内未启用的用户将按比例按月计费。", "admin.billing.subscriptions.billing_summary.noBillingHistory.description": "将来,这是您最近的帐单摘要将显示的位置。", "admin.billing.subscriptions.billing_summary.noBillingHistory.link": "查看计费方式", "admin.billing.subscriptions.billing_summary.noBillingHistory.title": "尚无帐单记录", + "admin.billing.subscriptions.billing_summary.try_enterprise": "免费试用企业版功能", + "admin.billing.subscriptions.billing_summary.try_enterprise.cta": "免费试用{trialLength} 天", + "admin.billing.subscriptions.billing_summary.upcomingInvoice.has_more_line_items": "有{count}更多条目", + "admin.billing.subscriptions.billing_summary.upgrade_professional": "升级至专业套餐", + "admin.billing.subscriptions.billing_summary.upgrade_professional.cta": "升级", + "admin.billing.trueUpReview.button_download": "下载数据", + "admin.billing.trueUpReview.button_share": "分享到Mattermost", + "admin.billing.trueUpReview.docsLinkCTA": "了解更多关于true-up.", + "admin.billing.trueUpReview.due_date": "到期 ", + "admin.billing.trueUpReview.share_data_for_review": "与Mattermost分享您的系统统计数据以进行季度的True-Up审核。{link}", + "admin.billing.trueUpReview.submit.thanks_for_sharing": "谢谢您分享与True-Up审核相关的数据。", + "admin.billing.trueUpReview.submit_error": "发送您的TrueUp审核时发生错误。请重试。", + "admin.billing.trueUpReview.submit_success": "成功!", + "admin.billing.trueUpReview.title": "True Up审核", "admin.bleve.bulkIndexingTitle": "批量索引:", "admin.bleve.createJob.help": "数据库中所有的用户、频道以及消息将从旧到新顺序索引。Bleve 可以在索引过程中使用但搜索结果可能不完整。", "admin.bleve.createJob.title": "立刻索引", @@ -530,6 +558,7 @@ "admin.cluster.status_table.url": "Gossip 地址", "admin.cluster.status_table.version": "版本", "admin.cluster.unknown": "未知", + "admin.cluster.version_mismatch_warning": "警告:您的高可用集群检测出多个版本的Mattermost。如果您不是正在进行升级,请确认集群所有的节点使用相同的Mattermost版本,以防平台功能异常。", "admin.compliance.complianceMonitoring": "合规监视", "admin.compliance.directoryDescription": "用户保存守规报告。如果为空,将被设置为 ./data/。", "admin.compliance.directoryExample": "例如 \"./data/\"", @@ -603,6 +632,8 @@ "admin.connectionSecurityTlsDescription": "加密Mattermost和您的服务器之间的通信。", "admin.custom_terms_of_service_feature_discovery.copy": "创建您自己的服务条款,新用户在访问桌面、网页或移动设备上的 Mattermost 之前必须接受该条款。", "admin.custom_terms_of_service_feature_discovery.title": "使用 Mattermost Enterprise 创建自定义服务条款", + "admin.customization.allowSyncedDrafts": "开启服务端草稿消息同步:", + "admin.customization.allowSyncedDraftsDesc": "当开启,用户的消息草稿将同步至服务端,所有的设备都可以看到。用户可以在帐户设置里关闭这个功能。", "admin.customization.androidAppDownloadLinkDesc": "添加安卓应用下载链接。用移动设备访问的用户将看到应用下载提示页面。此栏留空将不显示。", "admin.customization.androidAppDownloadLinkTitle": "安卓应用下载链接:", "admin.customization.announcement.allowBannerDismissalDesc": "当设为是时,用户可以撤掉横幅直到下次更新。当设为否时,横幅将永久显示直到被系统管理员关闭。", @@ -632,6 +663,8 @@ "admin.customization.enableLinkPreviewsTitle": "启用网站链接预览:", "admin.customization.enablePermalinkPreviewsDesc": "启用后,指向 Mattermost 消息的链接将为有权访问原始消息的任何用户生成预览。请查看我们的文档了解详细信息。", "admin.customization.enablePermalinkPreviewsTitle": "开启消息链接预览:", + "admin.customization.enablePublicSharedBoardsDesc": "此项允许面板编辑使用链接分享面板给所有人访问。", + "admin.customization.enablePublicSharedBoardsTitle": "启用公共访问面板:", "admin.customization.enableSVGsDesc": "开启 SVG 附件预览并让它们显示在消息中。", "admin.customization.enableSVGsTitle": "开启 SVG:", "admin.customization.gfycatApiKey": "Gfycat API Key:", @@ -707,6 +740,12 @@ "admin.database.title": "数据库", "admin.developer.title": "开发人员设置", "admin.elasticsearch.bulkIndexingTitle": "批量索引:", + "admin.elasticsearch.caExample": "例:\"./elasticsearch/ca.pem\"", + "admin.elasticsearch.caTitle": "CA path:", + "admin.elasticsearch.clientCertExample": "例:\"./elasticsearch/client-cert.pem\"", + "admin.elasticsearch.clientCertTitle": "客户端证书路径:", + "admin.elasticsearch.clientKeyExample": "例:\"./elasticsearch/client-cert.pem\"", + "admin.elasticsearch.clientKeyTitle": "客户端证书钥匙路径:", "admin.elasticsearch.connectionUrlDescription": "Elasticsearch 服务器地址。{documentationLink}", "admin.elasticsearch.connectionUrlExample": "例如:\"https://elasticsearch.example.org:9200\"", "admin.elasticsearch.connectionUrlExample.documentationLinkText": "请见服务器架设说明文档。", @@ -797,6 +836,9 @@ "admin.environment.notifications.replyToAddress.label": "通知 Reply-To 地址:", "admin.environment.notifications.replyToAddress.placeholder": "例如:\"mattermost@yourcompany.com\", \"admin@yourcompany.com\"", "admin.environment.notifications.supportAddress.placeholder": "例:“support@yourcompany.com”,“admin@yourcompany.com”", + "admin.environment.notifications.supportEmail.help": "客户支持邮件里显示的电子邮件地址。", + "admin.environment.notifications.supportEmail.label": "客户支持邮件地址:", + "admin.environment.notifications.supportEmail.required": "需要“客户支持电子邮件地址”", "admin.environment.pushNotificationServer": "推送通知服务器", "admin.environment.smtp": "SMTP", "admin.environment.smtp.connectionSecurity.option.none": "无", @@ -811,6 +853,7 @@ "admin.environment.smtp.smtpAuth.description": "当设为是时,开启 SMTP 验证。", "admin.environment.smtp.smtpAuth.title": "开启 SMTP 验证:", "admin.environment.smtp.smtpFail": "连接失败:{error}", + "admin.environment.smtp.smtpFailure": "SMTP没有在在系统控制台里配置。可以在 这里配置。", "admin.environment.smtp.smtpPassword.description": "从邮件服务器管理员获得此凭据。", "admin.environment.smtp.smtpPassword.placeholder": "例如:\"yourpassword\"、\"jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY\"", "admin.environment.smtp.smtpPassword.title": "SMTP 服务器密码:", @@ -4126,7 +4169,7 @@ "team_settings_modal.title": "团队设置", "team_sidebar.join": "您可以加入的其他团队", "terms_of_service.agreeButton": "我同意", - "terms_of_service.api_error": "无法完成请求。如果此问题持续,请联系您的系统管理员。", + "terms_of_service.api_error": "无法完成请求。如果此问题仍然存在,请联系您的系统管理员。", "terms_of_service.disagreeButton": "我不同意", "test": "文本按钮", "textbox.bold": "**加粗**", From 57eba3423ba98781ecc4b3dd73d29b4e9c94e5ec Mon Sep 17 00:00:00 2001 From: Pantelis Vratsalis Date: Tue, 4 Apr 2023 09:37:21 +0200 Subject: [PATCH 29/58] Translated using Weblate (Spanish) Currently translated at 89.5% (5152 of 5754 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/es/ --- webapp/channels/src/i18n/es.json | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/channels/src/i18n/es.json b/webapp/channels/src/i18n/es.json index bc69dc4c80..9eb429a031 100644 --- a/webapp/channels/src/i18n/es.json +++ b/webapp/channels/src/i18n/es.json @@ -5113,6 +5113,7 @@ "widgets.users_emails_input.loading": "Cargando", "widgets.users_emails_input.no_user_found_matching": "No se ha encontrado a nadie que coincida con **{text}**. Introduce su correo electrónico para invitarle.", "widgets.users_emails_input.valid_email": "Agregar **{email}**", + "work_templates.preview.section.included": "included sp", "workspace_limits.archived_file.archived_compact": "(archivado)", "workspace_limits.file_storage": "Almacenamiento de archivos", "workspace_limits.file_storage.short": "Archivos", From aef364c1d05f64d41616a6fdd60003f88fb4cdf4 Mon Sep 17 00:00:00 2001 From: Vadim Kazantsev Date: Tue, 4 Apr 2023 09:37:22 +0200 Subject: [PATCH 30/58] Translated using Weblate (Russian) Currently translated at 99.8% (5745 of 5754 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ru/ --- webapp/channels/src/i18n/ru.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/channels/src/i18n/ru.json b/webapp/channels/src/i18n/ru.json index 868acc19cd..52a3f21f7e 100644 --- a/webapp/channels/src/i18n/ru.json +++ b/webapp/channels/src/i18n/ru.json @@ -5086,7 +5086,7 @@ "threadFromArchivedChannelMessage": "Вы просматриваете обсуждение в **архивированном канале**. На этом канале нельзя опубликовать новые сообщения.", "threading.filters.allThreads": "Все ваши треды", "threading.filters.unreads": "Непрочитанное", - "threading.following": "Отслеживание", + "threading.following": "Отслеживается", "threading.footer.lastReplyAt": "Последний ответ {formatted}", "threading.header.heading": "Тред", "threading.notFollowing": "Отслеживать", @@ -5104,7 +5104,7 @@ "threading.threadMenu.markUnread": "Пометить как непрочитанное", "threading.threadMenu.openInChannel": "Открыт в канале", "threading.threadMenu.save": "Сохранить", - "threading.threadMenu.unfollow": "Отключить отслеживание треда", + "threading.threadMenu.unfollow": "Прекратить отслеживание треда", "threading.threadMenu.unfollowExtra": "Вы не будете уведомлены об ответах", "threading.threadMenu.unfollowMessage": "Отписаться от сообщения", "threading.threadMenu.unsave": "Убрать из сохраненных", From 26e74f92ec1fbf3524a9a1adc5e37c22c0bcd459 Mon Sep 17 00:00:00 2001 From: Ji-Hyeon Gim Date: Tue, 4 Apr 2023 09:37:22 +0200 Subject: [PATCH 31/58] Translated using Weblate (Korean) Currently translated at 83.1% (2105 of 2533 strings) Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/ko/ --- server/i18n/ko.json | 336 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) diff --git a/server/i18n/ko.json b/server/i18n/ko.json index 0e91deea0c..334d884c2f 100644 --- a/server/i18n/ko.json +++ b/server/i18n/ko.json @@ -8094,5 +8094,341 @@ { "id": "api.config.update_config.translations.app_error", "translation": "서버 번역 업데이트가 실패하였습니다." + }, + { + "id": "api.user.create_user.bad_token_email_data.app_error", + "translation": "토큰의 전자우편 주소가 사용자 데이터의 전자우편 주소와 일치하지 않습니다." + }, + { + "id": "api.user.authorize_oauth_user.saml_response_too_long.app_error", + "translation": "SAML 응답이 너무 깁니다" + }, + { + "id": "api.user.add_user_to_group_syncables.not_ldap_user.app_error", + "translation": "LDAP 사용자가 아님" + }, + { + "id": "api.upload.upload_data.multipart_error", + "translation": "멀티파트 데이터를 처리하지 못했습니다." + }, + { + "id": "api.upload.upload_data.invalid_content_type", + "translation": "멀티파트 업로드에 대한 Content-Type이 잘못되었습니다." + }, + { + "id": "api.upload.upload_data.invalid_content_length", + "translation": "유효하지 않은 Content-Length입니다." + }, + { + "id": "api.upload.get_upload.forbidden.app_error", + "translation": "업로드에 실패했습니다." + }, + { + "id": "api.upload.create.upload_too_large.app_error", + "translation": "파일을 업로드할 수 없습니다. 파일이 너무 큽니다." + }, + { + "id": "api.unable_to_read_file_from_backend", + "translation": "백엔드에서 파일 읽기 오류" + }, + { + "id": "api.templates.welcome_body.subTitle2", + "translation": "아래를 클릭하여 전자우편 주소를 인증하세요." + }, + { + "id": "api.templates.welcome_body.info1", + "translation": "수신자가 당신이 아닌 경우, 이 전자우편은 무시해도 됩니다." + }, + { + "id": "api.templates.verify_body.subTitle2", + "translation": "아래를 클릭하여 전자우편 주소를 인증하세요." + }, + { + "id": "api.templates.verify_body.subTitle1", + "translation": "참여해 주셔서 감사합니다 " + }, + { + "id": "api.templates.verify_body.serverURL", + "translation": "{{ .ServerURL }}." + }, + { + "id": "api.templates.verify_body.info1", + "translation": "수신자가 당신이 아닌 경우, 이 전자우편은 무시해도 됩니다." + }, + { + "id": "api.templates.reset_body.subTitle", + "translation": "비밀번호를 재설정하려면 아래 버튼을 클릭하세요. 요청하지 않은 경우 이 전자우편은 무시해도 됩니다." + }, + { + "id": "api.templates.reset_body.info", + "translation": "비밀번호 재설정 링크는 24시간 후에 만료됩니다." + }, + { + "id": "api.templates.questions_footer.title", + "translation": "질문이 있으신가요?" + }, + { + "id": "api.templates.questions_footer.info", + "translation": "도움이 필요하거나 질문이 있으신가요? 다음 주소로 전자우편을 보내주세요 " + }, + { + "id": "api.templates.payment_failed_no_card.title", + "translation": "Mattermost Cloud 청구서 마감일" + }, + { + "id": "api.templates.payment_failed_no_card.subject", + "translation": "Mattermost Cloud 구독에 대한 결제가 완료되었습니다" + }, + { + "id": "api.templates.payment_failed_no_card.info3", + "translation": "청구서를 검토하고 결제 방법을 추가하려면 지금 결제를 선택합니다." + }, + { + "id": "api.templates.payment_failed_no_card.info1", + "translation": "가장 최근 청구 기간에 대한 Mattermost Cloud 청구서가 처리되었습니다. 하지만 결제 세부 정보가 등록되어 있지 않습니다." + }, + { + "id": "api.templates.payment_failed_no_card.button", + "translation": "지금 결제하기" + }, + { + "id": "api.templates.payment_failed.title", + "translation": "결제가 성공하지 못했습니다" + }, + { + "id": "api.templates.payment_failed.info2", + "translation": "그들은 다음과 같은 이유를 제시했습니다:" + }, + { + "id": "api.templates.license_up_for_renewal_title", + "translation": "Mattermost 구독이 갱신될 예정입니다" + }, + { + "id": "api.templates.license_up_for_renewal_subtitle_two", + "translation": "갱신하려면 고객 계정으로 로그인하세요" + }, + { + "id": "api.templates.license_up_for_renewal_subject", + "translation": "라이선스 갱신 기간 만료" + }, + { + "id": "api.templates.license_up_for_renewal_contact_sales", + "translation": "영업팀에 문의" + }, + { + "id": "api.templates.invite_body_guest.subTitle", + "translation": "팀과의 공동 작업을 위해 게스트로 초대되었습니다" + }, + { + "id": "api.templates.invite_body_footer.info", + "translation": "Mattermost는 안전한 팀 협업을 지원하는 유연한 오픈소스 메시징 플랫폼입니다." + }, + { + "id": "api.templates.email_us_anytime_at", + "translation": "언제든지 다음 주소로 전자우편을 보내주세요 " + }, + { + "id": "api.templates.delinquency_90.title", + "translation": "Mattermost 워크스페이스가 다운그레이드되었습니다" + }, + { + "id": "api.templates.delinquency_90.subtitle2", + "translation": "또한 Cloud Free 제한으로 인해 데이터가 보관 처리되었을 수도 있습니다." + }, + { + "id": "api.templates.delinquency_90.subtitle3", + "translation": "데이터 보관을 해제하고 유료 기능을 계속 사용하려면 결제 정보를 업데이트하세요." + }, + { + "id": "api.templates.delinquency_90.subtitle1", + "translation": "중요한 비즈니스 운영에 Cloud Professional 또는 Enterprise 기능을 사용하는 경우 이러한 기능을 더 이상 사용할 수 없으며 성능이 저하됩니다." + }, + { + "id": "api.templates.delinquency_90.subject", + "translation": "Mattermost Cloud 워크스페이스가 다운그레이드되었습니다" + }, + { + "id": "api.templates.delinquency_90.secondary_action_button", + "translation": "플랜과 가격 보기" + }, + { + "id": "api.templates.delinquency_75.subtitle3", + "translation": "지금 결제 정보를 업데이트하거나 Cloud Free로 다운그레이드하세요." + }, + { + "id": "api.templates.delinquency_75.title", + "translation": "워크스페이스가 15일 후에 다운그레이드됩니다" + }, + { + "id": "api.templates.delinquency_90.button", + "translation": "결제 갱신" + }, + { + "id": "api.templates.delinquency_75.subject", + "translation": "Mattermost {{.Plan}} 플랜이 15일 후에 다운그레이드됩니다" + }, + { + "id": "api.templates.delinquency_75.downgrade_to_free", + "translation": "Cloud Free로 다운그레이드" + }, + { + "id": "api.templates.delinquency_75.button", + "translation": "결제 갱신" + }, + { + "id": "api.templates.delinquency_7.title", + "translation": "결제가 완료되지 않았습니다" + }, + { + "id": "api.templates.delinquency_7.subtitle1", + "translation": "가장 최근 결제를 처리하지 못했습니다." + }, + { + "id": "api.templates.delinquency_7.button", + "translation": "결제 갱신" + }, + { + "id": "api.templates.delinquency_60.title", + "translation": "Mattermost 워크스페이스가 30일 후에 다운그레이드됩니다" + }, + { + "id": "api.templates.delinquency_30.limits_documentation", + "translation": "모든 제한 문서 보기." + }, + { + "id": "api.templates.delinquency_30.button", + "translation": "결제 갱신" + }, + { + "id": "api.templates.delinquency_30.bullet.message_history", + "translation": "메시지 역사" + }, + { + "id": "api.templates.delinquency_30.bullet.files", + "translation": "파일" + }, + { + "id": "api.server.warn_metric.number_of_posts_2M.notification_title", + "translation": "성능 향상" + }, + { + "id": "api.server.warn_metric.number_of_teams_5.notification_title", + "translation": "고급 권한 사용 중" + }, + { + "id": "api.server.warn_metric.number_of_teams_5.start_trial_notification_success.message", + "translation": "엔터프라이즈 체험판이 활성화되었습니다. **시스템 콘솔 > 사용자 관리 > 권한** 에서 고급 권한 설정을 활성화하세요." + }, + { + "id": "api.system.logs.invalidFilter", + "translation": "유효하지 않은 로그 필터" + }, + { + "id": "api.team.add_team_member.invalid_body.app_error", + "translation": "요청 본문을 구문 분석할 수 없습니다." + }, + { + "id": "api.team.import_team.unknown_import_from.app_error", + "translation": "알 수 없는 들여오기 원본입니다." + }, + { + "id": "api.team.invite_guests_to_channels.disabled.error", + "translation": "게스트 계정이 비활성화되었습니다" + }, + { + "id": "api.team.invite_guests_to_channels.invalid_body.app_error", + "translation": "요청 본문이 유효하지 않거나 누락되었습니다." + }, + { + "id": "api.team.invite_guests_to_channels.license.error", + "translation": "게스트 계정을 지원하지 않는 라이선스입니다" + }, + { + "id": "api.team.invite_members.unable_to_send_email.app_error", + "translation": "전자우편을 보내는 중에 오류가 발생했습니다" + }, + { + "id": "api.team.invite_members.unable_to_send_email_with_defaults.app_error", + "translation": "시스템 콘솔에서 SMTP가 설정되지 않았습니다" + }, + { + "id": "api.team.invite_members_to_team_and_channels.invalid_body.app_error", + "translation": "유효하지 않은 요청 본문입니다." + }, + { + "id": "api.team.invite_members_to_team_and_channels.invalid_body_parsing.app_error", + "translation": "본문 데이터를 구문 분석하는 동안 오류가 발생했습니다." + }, + { + "id": "api.team.set_team_icon.check_image_limits.app_error", + "translation": "이미지 제한 확인에 실패했습니다. 해상도가 너무 높습니다." + }, + { + "id": "api.templates.cloud_upgrade_confirmation.subject", + "translation": "Mattermots 업그레이드 확인" + }, + { + "id": "api.templates.cloud_upgrade_confirmation.title", + "translation": "업그레이드 되었습니다!" + }, + { + "id": "api.templates.cloud_upgrade_confirmation_monthly.subtitle", + "translation": "{{.WorkspaceName}} 워크스페이스가 업그레이드 되었습니다. {{.Data}}에 결제가 됩니다" + }, + { + "id": "api.templates.cloud_upgrade_confirmation_yearly.subtitle", + "translation": "{{.WorkspaceName}} 워크스페이스가 업그레이드 되었습니다." + }, + { + "id": "api.templates.cloud_welcome_email.add_apps_info", + "translation": "워크스페이스에 앱들을 추가합니다" + }, + { + "id": "api.templates.cloud_welcome_email.app_market_place", + "translation": "앱 마켓플레이스." + }, + { + "id": "api.templates.cloud_welcome_email.button", + "translation": "매터모스트 열기" + }, + { + "id": "api.license.request-trial.can-start-trial.error", + "translation": "평가판을 시작할 수 있는지 확인할 수 없습니다" + }, + { + "id": "api.insights.feature_disabled", + "translation": "" + }, + { + "id": "api.file.test_connection_s3_settings_nil.app_error", + "translation": "파일 저장소 설정에 설정되지 않은 값이 있습니다." + }, + { + "id": "api.error_set_first_admin_visit_marketplace_status", + "translation": "스토어에 초기 관리자 마켓플레이스 방문 상태를 저장하는 동안 오류가 발생했습니다." + }, + { + "id": "api.command_templates.unsupported.app_error", + "translation": "이 장치에서는 템플릿 명령이 지원되지 않습니다." + }, + { + "id": "api.command_templates.name", + "translation": "템플릿" + }, + { + "id": "api.command_templates.desc", + "translation": "템플릿에서 만들기 창을 엽니다" + }, + { + "id": "api.acknowledgement.save.archived_channel.app_error", + "translation": "보관된 채널에서는 승인할 수 없습니다." + }, + { + "id": "api.acknowledgement.delete.deadline.app_error", + "translation": "5분이 경과한 후에는 확인을 삭제할 수 없습니다." + }, + { + "id": "api.acknowledgement.delete.archived_channel.app_error", + "translation": "보관된 채널에서는 승인 내용을 삭제할 수 없습니다." } ] From 3000926e81a84751607188c7bd25399a9ad59dcb Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 4 Apr 2023 09:37:24 +0200 Subject: [PATCH 32/58] Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/ Update translation files Updated by "Remove blank strings" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server-monorepo/ --- server/i18n/de.json | 4 ---- server/i18n/en_AU.json | 4 ---- server/i18n/ja.json | 4 ---- server/i18n/ko.json | 4 ---- server/i18n/nl.json | 4 ---- server/i18n/pl.json | 4 ---- server/i18n/ru.json | 4 ---- server/i18n/sv.json | 4 ---- server/i18n/tr.json | 4 ---- server/i18n/zh-CN.json | 4 ---- webapp/channels/src/i18n/bg.json | 2 -- webapp/channels/src/i18n/de.json | 7 ------- webapp/channels/src/i18n/en_AU.json | 6 ------ webapp/channels/src/i18n/es.json | 6 ------ webapp/channels/src/i18n/fa.json | 6 ------ webapp/channels/src/i18n/fr.json | 6 ------ webapp/channels/src/i18n/hu.json | 6 ------ webapp/channels/src/i18n/it.json | 2 -- webapp/channels/src/i18n/ja.json | 6 ------ webapp/channels/src/i18n/ko.json | 2 -- webapp/channels/src/i18n/nl.json | 6 ------ webapp/channels/src/i18n/pl.json | 6 ------ webapp/channels/src/i18n/pt-BR.json | 2 -- webapp/channels/src/i18n/ro.json | 2 -- webapp/channels/src/i18n/ru.json | 6 ------ webapp/channels/src/i18n/sv.json | 6 ------ webapp/channels/src/i18n/tr.json | 6 ------ webapp/channels/src/i18n/uk.json | 1 - webapp/channels/src/i18n/zh-CN.json | 5 ----- webapp/channels/src/i18n/zh-TW.json | 2 -- 30 files changed, 131 deletions(-) diff --git a/server/i18n/de.json b/server/i18n/de.json index 4a855acfb4..3e7aed88f5 100644 --- a/server/i18n/de.json +++ b/server/i18n/de.json @@ -9534,10 +9534,6 @@ "id": "app.post_prority.get_for_post.app_error", "translation": "Die Priorität der Nachricht kann nicht ermittelt werden" }, - { - "id": "app.draft.update.app_error", - "translation": "Die Aktualisierung des Entwurfs ist nicht möglich." - }, { "id": "app.draft.save.app_error", "translation": "Der Entwurf kann nicht gespeichert werden." diff --git a/server/i18n/en_AU.json b/server/i18n/en_AU.json index c686ba1acc..8a71e91c0d 100644 --- a/server/i18n/en_AU.json +++ b/server/i18n/en_AU.json @@ -9542,10 +9542,6 @@ "id": "app.post_prority.get_for_post.app_error", "translation": "Unable to get post priority for post" }, - { - "id": "app.draft.update.app_error", - "translation": "Unable to update the draft." - }, { "id": "app.draft.save.app_error", "translation": "Unable to save the draft." diff --git a/server/i18n/ja.json b/server/i18n/ja.json index c30ce9288b..58aa66d022 100644 --- a/server/i18n/ja.json +++ b/server/i18n/ja.json @@ -9519,10 +9519,6 @@ "id": "app.post_prority.get_for_post.app_error", "translation": "投稿に対する優先度を取得できませんでした" }, - { - "id": "app.draft.update.app_error", - "translation": "下書きを更新できませんでした。" - }, { "id": "app.draft.save.app_error", "translation": "下書きを保存できませんでした。" diff --git a/server/i18n/ko.json b/server/i18n/ko.json index 334d884c2f..ddd30b9753 100644 --- a/server/i18n/ko.json +++ b/server/i18n/ko.json @@ -8395,10 +8395,6 @@ "id": "api.license.request-trial.can-start-trial.error", "translation": "평가판을 시작할 수 있는지 확인할 수 없습니다" }, - { - "id": "api.insights.feature_disabled", - "translation": "" - }, { "id": "api.file.test_connection_s3_settings_nil.app_error", "translation": "파일 저장소 설정에 설정되지 않은 값이 있습니다." diff --git a/server/i18n/nl.json b/server/i18n/nl.json index 46f05f6239..95097c7095 100644 --- a/server/i18n/nl.json +++ b/server/i18n/nl.json @@ -9562,10 +9562,6 @@ "id": "app.post_prority.get_for_post.app_error", "translation": "Kon geen berichtprioriteit ophalen voor bericht" }, - { - "id": "app.draft.update.app_error", - "translation": "Kan het concept niet bijwerken." - }, { "id": "app.draft.save.app_error", "translation": "Kan het concept niet opslaan." diff --git a/server/i18n/pl.json b/server/i18n/pl.json index abf9d3be2d..339c00b48b 100644 --- a/server/i18n/pl.json +++ b/server/i18n/pl.json @@ -9539,10 +9539,6 @@ "id": "app.post_prority.get_for_post.app_error", "translation": "Nie można uzyskać priorytetu dla posta" }, - { - "id": "app.draft.update.app_error", - "translation": "Nie można zaktualizować szkicu." - }, { "id": "app.draft.save.app_error", "translation": "Nie można zapisać Szkicu." diff --git a/server/i18n/ru.json b/server/i18n/ru.json index 9a214093d2..452811806c 100644 --- a/server/i18n/ru.json +++ b/server/i18n/ru.json @@ -9539,10 +9539,6 @@ "id": "app.post_prority.get_for_post.app_error", "translation": "Невозможно получить приоритет для сообщения" }, - { - "id": "app.draft.update.app_error", - "translation": "Невозможно обновить черновик." - }, { "id": "app.draft.save.app_error", "translation": "Невозможно сохранить черновик." diff --git a/server/i18n/sv.json b/server/i18n/sv.json index 03d73e6a12..f63afba27a 100644 --- a/server/i18n/sv.json +++ b/server/i18n/sv.json @@ -9586,10 +9586,6 @@ "id": "app.post_prority.get_for_post.app_error", "translation": "Det går inte att få fram inläggets prioritet" }, - { - "id": "app.draft.update.app_error", - "translation": "Kunde inte uppdatera utkastet." - }, { "id": "app.draft.save.app_error", "translation": "Kunde inte spara utkastet." diff --git a/server/i18n/tr.json b/server/i18n/tr.json index 84e7ffedc7..218846ffc4 100644 --- a/server/i18n/tr.json +++ b/server/i18n/tr.json @@ -9566,10 +9566,6 @@ "id": "app.post_prority.get_for_post.app_error", "translation": "İletinin önceliği alınamadı" }, - { - "id": "app.draft.update.app_error", - "translation": "Taslak güncellenemedi." - }, { "id": "app.draft.get_drafts.app_error", "translation": "Kullanıcının taslakları alınamadı." diff --git a/server/i18n/zh-CN.json b/server/i18n/zh-CN.json index 5eb04cde8f..bbf95c2889 100644 --- a/server/i18n/zh-CN.json +++ b/server/i18n/zh-CN.json @@ -9667,10 +9667,6 @@ "id": "app.file.cloud.get.app_error", "translation": "由于云订阅的限制,无法取得文件。" }, - { - "id": "app.draft.update.app_error", - "translation": "无法更新草稿。" - }, { "id": "app.draft.save.app_error", "translation": "无法保存草稿。" diff --git a/webapp/channels/src/i18n/bg.json b/webapp/channels/src/i18n/bg.json index 7a45713834..f5f826761a 100644 --- a/webapp/channels/src/i18n/bg.json +++ b/webapp/channels/src/i18n/bg.json @@ -2362,7 +2362,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} премахна целта на канала (беше: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} актуализира целта на канала от: {old} до: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} актуализира целта на канала до: {new}", - "app.plugin.marketplace_plugins.app_error": "Грешка при свързване със сървъра на пазара. Моля, проверете настройките си в [Системна конзола]({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Грешка: {error}", "apps.error.command.field_missing": "Липсват задължителни полета: `{fieldName}`.", "apps.error.command.same_channel": "Повтаря се каналът с поле `{fieldName}`: `{option}`.", @@ -3414,7 +3413,6 @@ "login_mfa.token": "МФУ маркер", "manage_channel_groups_modal.search_placeholder": "Търсене на групи", "manage_team_groups_modal.search_placeholder": "Търсене на групи", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {приставка} other {приставки}} от {total, number} общо", "marketplace_modal.install_plugins": "Инсталирай приставки", "marketplace_modal.installing": "Инсталиране ...", "marketplace_modal.list.configure": "Конфигуриране", diff --git a/webapp/channels/src/i18n/de.json b/webapp/channels/src/i18n/de.json index 847c1455d7..f1839cf072 100644 --- a/webapp/channels/src/i18n/de.json +++ b/webapp/channels/src/i18n/de.json @@ -2651,7 +2651,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} hat den Kanalzweck entfernt (war: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} hat den Kanalzweck aktualisiert von: {old} auf: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} hat den Kanalzweck geändert zu: {new}", - "app.plugin.marketplace_plugins.app_error": "Fehler beim Verbinden mit dem Marktplatz-Server. Bitte überprüfe deine Einstellungen in der [Systemkonsole]({siteURL}/admin_console/plugins/plugin_management).", "app_bar.marketplace": "App-Marktplatz", "apps.error": "Fehler: {error}", "apps.error.command.field_missing": "Erforderliche Felder fehlen: `{fieldName}`.", @@ -4085,7 +4084,6 @@ "mark_all_threads_as_read_modal.title": "Alle deine Unterhaltungen als gelesen markieren?", "marketplace_command.disabled": "Der Marktplatz ist deaktiviert. Bitte kontaktiere deinen Systemadmin für Details.", "marketplace_command.no_permission": "Du hast nicht die erforderlichen Berechtigungen um auf den Marktplatz zuzugreifen.", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {Plugin} other {Plugins}} von insgesamt {total, number}", "marketplace_modal.install_plugins": "Plugins installieren", "marketplace_modal.installing": "Installiere...", "marketplace_modal.list.configure": "Konfigurieren", @@ -4289,7 +4287,6 @@ "onboardingTask.checklist.downloads": "Jetzt, da du alles konfiguriert hast, lade unsere Apps runter.", "onboardingTask.checklist.higher_security_features": "Interessiert an unseren Hochsicherheitsfunktionen?", "onboardingTask.checklist.main_subtitle": "Legen wir los.", - "onboardingTask.checklist.no_tanks": "Nein, danke", "onboardingTask.checklist.start_enterprise_now": "Starte jetzt Deinen kostenfreien Enterprise-Test!", "onboardingTask.checklist.task_complete_your_profile": "Vervollständige dein Profil.", "onboardingTask.checklist.task_create_from_work_template": "Erstellen aus einer Vorlage", @@ -4978,11 +4975,7 @@ "start_trial.modal.gettingTrial": "Hole Test...", "start_trial.modal.loaded": "Geladen!", "start_trial.modal.loading": "Lade...", - "start_trial.modal_body": "Greife auf alle Plattform-Funktionen, inklusive erweiterter Sicherheit- und Unternehmens-Compliance, zu.", - "start_trial.modal_btn.nottnow": "Nicht jetzt", - "start_trial.modal_btn.start": "Starte dem freien 30-Tage Test", "start_trial.modal_btn.start_free_trial": "Kostenlose 30-Tage-Testversion starten", - "start_trial.modal_title": "Starte jetzt deine kostenlose Enterprise-Testversion", "start_trial.tutorialTip.desc": "Probiere unsere am meisten gefragten Premium Funktionen: Lege den Benutzerzugriff mit Gast-Konten fest, automatisiere Compliance Berichte und sende sichere, mobile Nur-ID Push-Nachrichten.", "start_trial.tutorialTip.title": "Teste kostenfrei Premium Funktionen", "start_trial_form.company_name": "Firmenname", diff --git a/webapp/channels/src/i18n/en_AU.json b/webapp/channels/src/i18n/en_AU.json index 2906491d72..628ed6d96c 100644 --- a/webapp/channels/src/i18n/en_AU.json +++ b/webapp/channels/src/i18n/en_AU.json @@ -2643,7 +2643,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} removed the channel purpose (was: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} updated the channel purpose from: {old} to: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} updated the channel purpose to: {new}", - "app.plugin.marketplace_plugins.app_error": "Error connecting to the marketplace server. Please check your settings in the [System Console]({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Error: {error}", "apps.error.command.field_missing": "Required fields missing: `{fieldName}`.", "apps.error.command.same_channel": "Channel repeated for field `{fieldName}`: `{option}`.", @@ -4076,7 +4075,6 @@ "mark_all_threads_as_read_modal.title": "Mark all your threads as read?", "marketplace_command.disabled": "The marketplace is disabled. Please contact your System Administrator for details.", "marketplace_command.no_permission": "You do not have the appropriate permissions to access the marketplace.", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {plugins}} of {total, number} total", "marketplace_modal.install_plugins": "Install Plugins", "marketplace_modal.installing": "Installing...", "marketplace_modal.list.configure": "Configure", @@ -4941,11 +4939,7 @@ "start_trial.modal.gettingTrial": "Getting Trial...", "start_trial.modal.loaded": "Loaded!", "start_trial.modal.loading": "Loading...", - "start_trial.modal_body": "Access all platform features including advanced security and enterprise compliance.", - "start_trial.modal_btn.nottnow": "Not now", - "start_trial.modal_btn.start": "Start a free 30-day trial", "start_trial.modal_btn.start_free_trial": "Start a free 30-day trial", - "start_trial.modal_title": "Start your free Enterprise trial now", "start_trial.tutorialTip.desc": "Explore our most requested premium features. Determine user access with Guest Accounts, automate compliance reports, and send secure ID-only mobile push notifications.", "start_trial.tutorialTip.title": "Try our premium features for free", "status_dropdown.dnd_sub_menu_header": "Disable notifications until:", diff --git a/webapp/channels/src/i18n/es.json b/webapp/channels/src/i18n/es.json index 9eb429a031..a29c97938c 100644 --- a/webapp/channels/src/i18n/es.json +++ b/webapp/channels/src/i18n/es.json @@ -2566,7 +2566,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} eliminó el propósito del canal (era: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} ha actualizado el propósito del canal de: {old} a: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} ha actualizado el propósito del canal a: {new}", - "app.plugin.marketplace_plugins.app_error": "Error de conexión con el servidor del marketplace. Por favor revisa los ajustes en la [Consola del Sistema]({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Error: {error}", "apps.error.command.field_missing": "Faltan campos obligatorios: `{fieldName}`.", "apps.error.command.same_channel": "Canal repetido para el campo `{fieldName}`: `{option}`.", @@ -3827,7 +3826,6 @@ "manage_channel_groups_modal.search_placeholder": "Buscar grupos", "manage_team_groups_modal.search_placeholder": "Buscar grupos", "mark_all_threads_as_read_modal.cancel": "Cancelar", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {plugins}} de {total, number} total", "marketplace_modal.install_plugins": "Instalar Plugins", "marketplace_modal.installing": "Instalando...", "marketplace_modal.list.configure": "Configurar", @@ -4491,11 +4489,7 @@ "start_trial.modal.gettingTrial": "Obteniendo Prueba...", "start_trial.modal.loaded": "¡Cargado!", "start_trial.modal.loading": "Cargando...", - "start_trial.modal_body": "Accede a todas las características de la plataforma incluyendo seguridad avanzada y cumplimiento empresarial.", - "start_trial.modal_btn.nottnow": "Ahora no", - "start_trial.modal_btn.start": "¡Comienza la pruba gratuita de 30 días", "start_trial.modal_btn.start_free_trial": "Comienza tu prueba gratuita de 30 días", - "start_trial.modal_title": "Comienza tu prueba gratuita Enterprise ahora", "start_trial.tutorialTip.title": "Prueba nuestras características premium de forma gratuita", "status_dropdown.dnd_sub_menu_header": "Desactivar las notificaciones hasta:", "status_dropdown.dnd_sub_menu_item.custom": "Personalizado", diff --git a/webapp/channels/src/i18n/fa.json b/webapp/channels/src/i18n/fa.json index 7a5e231090..40a31e2d1a 100644 --- a/webapp/channels/src/i18n/fa.json +++ b/webapp/channels/src/i18n/fa.json @@ -2403,7 +2403,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} هدف کانال را حذف کرد (بود: {قدیمی})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} هدف کانال را از: {old} به: {new} به‌روزرسانی کرد", "app.channel.post_update_channel_purpose_message.updated_to": "{username} هدف کانال را به‌روزرسانی کرد: {new}", - "app.plugin.marketplace_plugins.app_error": "خطا در اتصال به سرور بازار. لطفاً تنظیمات خود را در [System Console] ({siteURL}/admin_console/plugins/plugin_management) بررسی کنید.", "apps.error": "خطا: {error}", "apps.error.command.field_missing": "فیلدهای لازم وجود ندارد: `{fieldName}`.", "apps.error.command.same_channel": "تکرار کانال برای فیلد «{fieldName}»: «{option}».", @@ -3633,7 +3632,6 @@ "manage_channel_groups_modal.search_placeholder": "جستجو در گروه ها", "manage_team_groups_modal.search_placeholder": "جستجو در گروه ها", "mark_all_threads_as_read_modal.cancel": "لغو", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {plugins}} از مجموع {total, number}", "marketplace_modal.install_plugins": "پلاگین ها را نصب کنید", "marketplace_modal.installing": "در حال نصب...", "marketplace_modal.list.configure": "پیکربندی کنید", @@ -4281,10 +4279,6 @@ "start_trial.modal.gettingTrial": "در حال دریافت دوره آزمایشی...", "start_trial.modal.loaded": "لود شده!", "start_trial.modal.loading": "بارگذاری...", - "start_trial.modal_body": "به تمام ویژگی های پلت فرم از جمله امنیت پیشرفته و انطباق سازمانی دسترسی داشته باشید.", - "start_trial.modal_btn.nottnow": "الان نه", - "start_trial.modal_btn.start": "شروع آزمایشی 30 روزه", - "start_trial.modal_title": "اکنون آزمایشی رایگان Enterprise خود را شروع کنید", "status_dropdown.dnd_sub_menu_header": "غیرفعال کردن اعلان ها تا زمانی که:", "status_dropdown.dnd_sub_menu_item.custom": "سفارشی", "status_dropdown.dnd_sub_menu_item.one_hour": "1 ساعت", diff --git a/webapp/channels/src/i18n/fr.json b/webapp/channels/src/i18n/fr.json index 77d9b1a797..f499e597dc 100644 --- a/webapp/channels/src/i18n/fr.json +++ b/webapp/channels/src/i18n/fr.json @@ -2507,7 +2507,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} a supprimé la description du canal (précédemment : {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} a mis à jour la description du canal de : {old} en : {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} a mis à jour la description du canal en : {new}", - "app.plugin.marketplace_plugins.app_error": "Une erreur s'est produite lors de la connexion au serveur de place de marché. Veuillez vérifier vos paramètres dans la [Console du système]({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Erreur : {error}", "apps.error.command.field_missing": "Champs obligatoires manquants : `{fieldName}`.", "apps.error.command.same_channel": "Canal répété pour le champ `{fieldName}` : `{option}`.", @@ -3666,7 +3665,6 @@ "login_mfa.token": "Jeton d'authentification multi-facteurs (MFA)", "manage_channel_groups_modal.search_placeholder": "Rechercher des groupes", "manage_team_groups_modal.search_placeholder": "Rechercher des groupes", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {plugins}} sur un total de {total, number}", "marketplace_modal.install_plugins": "Installer des extensions", "marketplace_modal.installing": "Installation en cours...", "marketplace_modal.list.configure": "Configurer", @@ -4268,11 +4266,7 @@ "start_trial.modal.gettingTrial": "Obtention d'un essai...", "start_trial.modal.loaded": "Chargé !", "start_trial.modal.loading": "Chargement...", - "start_trial.modal_body": "Accédez à toutes les fonctionnalités de la plateforme, y compris la sécurité avancée et la conformité de l'entreprise.", - "start_trial.modal_btn.nottnow": "Pas maintenant", - "start_trial.modal_btn.start": "Commencer un essai gratuit de 30 jours", "start_trial.modal_btn.start_free_trial": "Commencez l'essai gratuit de 30 jours", - "start_trial.modal_title": "Commencez votre essai gratuit de la version Enterprise maintenant", "start_trial.tutorialTip.desc": "Explorez nos fonctionnalités premium les plus demandées. Déterminez l'accès des utilisateurs avec les comptes d'invités, automatisez les rapports de conformité et envoyez des notifications push mobiles sécurisées uniquement pour les identifiants.", "start_trial.tutorialTip.title": "Essayez gratuitement nos fonctionnalités premium", "status_dropdown.dnd_sub_menu_header": "Désactiver les notifications jusqu'à :", diff --git a/webapp/channels/src/i18n/hu.json b/webapp/channels/src/i18n/hu.json index 072b7fc7e5..4402385b81 100644 --- a/webapp/channels/src/i18n/hu.json +++ b/webapp/channels/src/i18n/hu.json @@ -2543,7 +2543,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} eltávolította a csatorna célját (volt: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} frissítette a csatorna célját: {old} -> {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} frissítette a csatorna célját erre: {new}", - "app.plugin.marketplace_plugins.app_error": "Hiba történt a piactér szerveréhez való csatlakozáskor. Kérjük, ellenőrizze a beállításait a [Rendszerkonzolban]({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Hiba: {error}", "apps.error.command.field_missing": "Hiányzó kötelező mezők: `{fieldName}`.", "apps.error.command.same_channel": "Beszélgetés ismételve lett a mezőhöz `{fieldName}`: `{option}`.", @@ -3845,7 +3844,6 @@ "login_mfa.token": "Többtényezős hitelesítés (MFA) token", "manage_channel_groups_modal.search_placeholder": "Csoportok keresése", "manage_team_groups_modal.search_placeholder": "Csoportok keresése", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} bővítmény / {total, number} összesen", "marketplace_modal.install_plugins": "Bővítmények telepítése", "marketplace_modal.installing": "Telepítés...", "marketplace_modal.list.configure": "Beállítás", @@ -4575,11 +4573,7 @@ "start_trial.modal.gettingTrial": "Próbaidőszak kezdése...", "start_trial.modal.loaded": "Betöltve!", "start_trial.modal.loading": "Betöltés...", - "start_trial.modal_body": "Férjen hozzá az összes platform szolgáltatáshoz beleértve a fejlett biztonságot és a vállalati megfelelősséget.", - "start_trial.modal_btn.nottnow": "Ne most", - "start_trial.modal_btn.start": "30 napos ingyenes próbaidőszak indítása", "start_trial.modal_btn.start_free_trial": "30 napos ingyenes próbaidőszak indítása", - "start_trial.modal_title": "Az ingyenes Enterprise kiadás próbaidőszak indítása", "start_trial.tutorialTip.desc": "Fedezze fel a legkeresettebb prémium funkcióinkat. Határozza meg a felhasználók hozzáférését a vendégfiókok segítségével, automatizálja a megfelelőségi jelentéseket, és küldjön biztonságos, csak azonosítóval ellátott mobil push-értesítéseket.", "start_trial.tutorialTip.title": "Próbálja ki prémium szolgáltatásainkat ingyen", "status_dropdown.dnd_sub_menu_header": "Értesítések kikapcsolása eddig:", diff --git a/webapp/channels/src/i18n/it.json b/webapp/channels/src/i18n/it.json index bcf1c47bc2..af4a0b1412 100644 --- a/webapp/channels/src/i18n/it.json +++ b/webapp/channels/src/i18n/it.json @@ -1969,7 +1969,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} ha cancellato lo scopo del canale (era: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} ha aggiornato lo scopo del canale da: {old} a: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} ha aggiornato lo scopo del canale a: {new}", - "app.plugin.marketplace_plugins.app_error": "Errore connessione al server marketplace. Controllare le impostazioni in [Console di Sistema]({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Errore: {error}", "apps.error.command.field_missing": "Campo richiesto mancante: `{fieldName}`.", "apps.error.command.same_channel": "Canale ripetuto per il campo `{fieldName}`: `{option}`.", @@ -2931,7 +2930,6 @@ "login_mfa.token": "Token MFA", "manage_channel_groups_modal.search_placeholder": "Cerca gruppi", "manage_team_groups_modal.search_placeholder": "Cerca gruppi", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {plugins}} di {total, number} totali", "marketplace_modal.install_plugins": "Installa Plugin", "marketplace_modal.installing": "Installazione...", "marketplace_modal.list.configure": "Configura", diff --git a/webapp/channels/src/i18n/ja.json b/webapp/channels/src/i18n/ja.json index 9c26b7387c..9ab8b3f551 100644 --- a/webapp/channels/src/i18n/ja.json +++ b/webapp/channels/src/i18n/ja.json @@ -2647,7 +2647,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} がチャンネルの目的({old})を削除しました", "app.channel.post_update_channel_purpose_message.updated_from": "{username} がチャンネルの目的を {old} から {new} へ更新しました", "app.channel.post_update_channel_purpose_message.updated_to": "{username} がチャンネルの目的を {new} へ更新しました", - "app.plugin.marketplace_plugins.app_error": "マーケットプレースサーバーへ接続する際にエラーが発生しました。[システムコンソール]({siteURL}/admin_console/plugins/plugin_management)内の設定を確認してください。", "apps.error": "エラー: {error}", "apps.error.command.field_missing": "必須フィールドが存在しません: `{fieldName}`。", "apps.error.command.same_channel": "フィールド `{fieldName}` でチャンネルが繰り返し指定されました: `{option}`。", @@ -4080,7 +4079,6 @@ "mark_all_threads_as_read_modal.title": "すべてのスレッドを既読にしますか?", "marketplace_command.disabled": "マーケットプレイスが無効になっています。詳しくは、システム管理者に問い合わせてください。", "marketplace_command.no_permission": "マーケットプレイスにアクセスするための適切な権限を持っていません。", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} 全 {total, number} プラグイン中", "marketplace_modal.install_plugins": "プラグインをインストールする", "marketplace_modal.installing": "インストールしています...", "marketplace_modal.list.configure": "設定", @@ -4966,11 +4964,7 @@ "start_trial.modal.gettingTrial": "トライアル開始中...", "start_trial.modal.loaded": "読み込みが完了しました!", "start_trial.modal.loading": "読み込み中です...", - "start_trial.modal_body": "高度なセキュリティとコンプライアンス機能を含むプラットフォームのすべての機能にアクセスできます。", - "start_trial.modal_btn.nottnow": "今はしない", - "start_trial.modal_btn.start": "30日間の無料トライアルを開始する", "start_trial.modal_btn.start_free_trial": "30日間の無料トライアルを開始する", - "start_trial.modal_title": "今すぐEnterprise版の無料トライアルを開始する", "start_trial.tutorialTip.desc": "最も要望の多いプレミアム機能を紹介します。ゲストアカウント、コンプライアンスレポートの自動化、IDのみを利用したセキュアなモバイルプッシュ通知。", "start_trial.tutorialTip.title": "プレミアム機能を無料でお試しいただけます", "status_dropdown.dnd_sub_menu_header": "通知を無効にする期間:", diff --git a/webapp/channels/src/i18n/ko.json b/webapp/channels/src/i18n/ko.json index 90f55a29e8..7f6391fcd7 100644 --- a/webapp/channels/src/i18n/ko.json +++ b/webapp/channels/src/i18n/ko.json @@ -2833,7 +2833,6 @@ "login_mfa.token": "MFA 토큰", "manage_channel_groups_modal.search_placeholder": "그룹 찾기", "manage_team_groups_modal.search_placeholder": "그룹 찾기", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {plugins}} of {total, number} total", "marketplace_modal.install_plugins": "설치된 플러그인", "marketplace_modal.installing": "설치중...", "marketplace_modal.list.configure": "설정", @@ -3172,7 +3171,6 @@ "signup_user_completed.validEmail": "유효한 전자우편 주소를 입력해주세요", "someting.string": "기본문자열", "start_trial.modal.loading": "로딩중...", - "start_trial.modal_btn.start": "30일 평가판 시작", "status_dropdown.menuAriaLabel": "set status", "status_dropdown.set_away": "다른 용무 중", "status_dropdown.set_dnd": "방해 금지", diff --git a/webapp/channels/src/i18n/nl.json b/webapp/channels/src/i18n/nl.json index b0b4efaf40..456a23818f 100644 --- a/webapp/channels/src/i18n/nl.json +++ b/webapp/channels/src/i18n/nl.json @@ -2645,7 +2645,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} verwijderde het kanaal doel (was: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} heeft het doel van het kanaal bijgewerkt van: {old} naar: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} heeft het kanaaldoel bijgewerkt naar: {new}", - "app.plugin.marketplace_plugins.app_error": "Fout bij het maken van verbinding met de marktplaats server. Controleer uw instellingen in de [Systeemconsole] ({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Fout: {error}", "apps.error.command.field_missing": "Verplichte velden ontbreken: `{fieldName}`.", "apps.error.command.same_channel": "Kanaal herhaald voor veld `{fieldName}`: `{option}`.", @@ -4078,7 +4077,6 @@ "mark_all_threads_as_read_modal.title": "Al jouw draadjes als gelezen markeren?", "marketplace_command.disabled": "De marktplaats is uitgeschakeld. Neem contact op met jouw systeembeheerder voor meer informatie.", "marketplace_command.no_permission": "Je hebt niet de juiste rechten om toegang te krijgen tot de marktplaats.", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {plugins}} van {total, number} in het totaal", "marketplace_modal.install_plugins": "Installeer Plugins", "marketplace_modal.installing": "Bezig met Installeren...", "marketplace_modal.list.configure": "Configureren", @@ -4963,11 +4961,7 @@ "start_trial.modal.gettingTrial": "Proefversie ophalen...", "start_trial.modal.loaded": "Geladen!", "start_trial.modal.loading": "Laden...", - "start_trial.modal_body": "Toegang tot alle platformfuncties, inclusief geavanceerde beveiliging en de nalevingsregels met de onderneming.", - "start_trial.modal_btn.nottnow": "Niet nu", - "start_trial.modal_btn.start": "Start gratis je 30-dagen proefperiode", "start_trial.modal_btn.start_free_trial": "Start je gratis 30-dagen proefperiode", - "start_trial.modal_title": "Start nu je gratis Enterprise-proefperiode", "start_trial.tutorialTip.desc": "Ontdek onze meest gevraagde premium-functies. Bepaal gebruikerstoegang met gastaccounts, automatiseer nalevingsrapporten en verstuur veilige mobiele pushmeldingen met alleen ID's.", "start_trial.tutorialTip.title": "Probeer onze premium-functies gratis", "status_dropdown.dnd_sub_menu_header": "Meldingen uitschakelen tot:", diff --git a/webapp/channels/src/i18n/pl.json b/webapp/channels/src/i18n/pl.json index f635806dba..09434f4323 100644 --- a/webapp/channels/src/i18n/pl.json +++ b/webapp/channels/src/i18n/pl.json @@ -2647,7 +2647,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} usunął cel kanału (było: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} zaktualizował cel kanału z: {old} na: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} zaktualizował cel kanału na: {new}", - "app.plugin.marketplace_plugins.app_error": "Błąd podczas łączenia z serwerem marketplace. Sprawdź ustawienia w [Konsoli systemowej] ({siteURL}/admin_console/plugins/plugin_management).", "app_bar.marketplace": "Sklep z Aplikacjami", "apps.error": "Błąd: {error}", "apps.error.command.field_missing": "Brakujące wymagane pola: `{fieldName}`.", @@ -4081,7 +4080,6 @@ "mark_all_threads_as_read_modal.title": "Oznaczyć wszystkie twoje wątki jako przeczytane?", "marketplace_command.disabled": "Sklep jest wyłączony. W celu uzyskania szczegółowych informacji należy skontaktować się z administratorem systemu.", "marketplace_command.no_permission": "Nie masz odpowiednich uprawnień, aby uzyskać dostęp do sklepu.", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {wtyczka} other {wtyczki}} z {total, number} wszystkich", "marketplace_modal.install_plugins": "Zainstaluj wtyczki", "marketplace_modal.installing": "Instalowanie...", "marketplace_modal.list.configure": "Konfiguruj", @@ -4973,11 +4971,7 @@ "start_trial.modal.gettingTrial": "Pobieranie wersji Testowej...", "start_trial.modal.loaded": "Załadowany!", "start_trial.modal.loading": "Ładowanie...", - "start_trial.modal_body": "Uzyskaj dostęp do wszystkich funkcji platformy, w tym zaawansowanych zabezpieczeń i zgodności korporacyjnej.", - "start_trial.modal_btn.nottnow": "Nie teraz", - "start_trial.modal_btn.start": "Rozpocznij bezpłatny 30-dniowy okres próbny", "start_trial.modal_btn.start_free_trial": "Rozpocznij bezpłatny 30-dniowy okres próbny", - "start_trial.modal_title": "Rozpocznij bezpłatny okres próbny Enterprise już teraz", "start_trial.tutorialTip.desc": "Zapoznaj się z naszymi najbardziej pożądanymi funkcjami premium. Określ dostęp użytkowników za pomocą kont gości, zautomatyzuj raporty zgodności i wysyłaj bezpieczne powiadomienia mobilne push z wykorzystaniem wyłącznie identyfikatorów.", "start_trial.tutorialTip.title": "Wypróbuj nasze funkcje premium za darmo", "status_dropdown.dnd_sub_menu_header": "Wyłącz powiadomienia do:", diff --git a/webapp/channels/src/i18n/pt-BR.json b/webapp/channels/src/i18n/pt-BR.json index 46f0c79dea..6e21aa2a99 100644 --- a/webapp/channels/src/i18n/pt-BR.json +++ b/webapp/channels/src/i18n/pt-BR.json @@ -2191,7 +2191,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} removeu o propósito do canal (era: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} atualizou o propósito do canal de: {old} para: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} atualizou o propósito do canal para: {new}", - "app.plugin.marketplace_plugins.app_error": "Erro ao conectar-se ao servidor do marketplace. Por favor, verifique suas configurações no [Console do Sistema]({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Erro: {error}", "apps.error.command.same_channel": "Canal repetido para o campo `{fieldName}`: `{option}`.", "apps.error.command.same_option": "Opção repetida para o campo `{fieldName}`: `{option}`.", @@ -3150,7 +3149,6 @@ "login_mfa.token": "Token MFA", "manage_channel_groups_modal.search_placeholder": "Buscar grupos", "manage_team_groups_modal.search_placeholder": "Buscar grupos", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {plugins}} de {total, number} total", "marketplace_modal.install_plugins": "Instalar Plugins", "marketplace_modal.installing": "Instalando...", "marketplace_modal.list.configure": "Configurar", diff --git a/webapp/channels/src/i18n/ro.json b/webapp/channels/src/i18n/ro.json index c637824455..450f29be22 100644 --- a/webapp/channels/src/i18n/ro.json +++ b/webapp/channels/src/i18n/ro.json @@ -2253,7 +2253,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} a eliminat scopul canalului (a fost: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} a actualizat scopul canalului de la: {old} la: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} a actualizat scopul canalului la: {new}", - "app.plugin.marketplace_plugins.app_error": "Eroare la conectarea la serverul de pe piață. Verificați setările din [Consola de sistem]({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Eroare: {error}", "apps.error.command.field_missing": "Câmpurile obligatorii lipsesc: `{fieldName}`.", "apps.error.command.unknown_channel": "Canal necunoscut pentru câmpul `{fieldName}`: `{option}`.", @@ -3236,7 +3235,6 @@ "login_mfa.token": "Eroare încearcă să se autentifice Mae token", "manage_channel_groups_modal.search_placeholder": "Căutați grupuri", "manage_team_groups_modal.search_placeholder": "Căutați grupuri", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {pluginuri}} din {total, number} total", "marketplace_modal.install_plugins": "Instalați pluginuri", "marketplace_modal.installing": "Se instalează ...", "marketplace_modal.list.configure": "Configurați", diff --git a/webapp/channels/src/i18n/ru.json b/webapp/channels/src/i18n/ru.json index 52a3f21f7e..228f9e88f4 100644 --- a/webapp/channels/src/i18n/ru.json +++ b/webapp/channels/src/i18n/ru.json @@ -2647,7 +2647,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} удалил заголовок канала (было: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} сменил заголовок канала с {old} на {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} установил заголовок канала: {new}", - "app.plugin.marketplace_plugins.app_error": "Ошибка подключения к серверу магазина плагинов. Проверьте свои настройки в [Системной консоли]({siteURL}/admin_console/plugins/plugin_management).", "apps.error": "Ошибка: {error}", "apps.error.command.field_missing": "Обязательные поля отсутствуют: `{fieldName}`.", "apps.error.command.same_channel": "Канал повторяется для поля `{fieldName}`: `{option}`.", @@ -4080,7 +4079,6 @@ "mark_all_threads_as_read_modal.title": "Пометить все свои обсуждения как прочитанные?", "marketplace_command.disabled": "Магазин плагинов отключен. Для получения подробной информации обратитесь к системному администратору.", "marketplace_command.no_permission": "У вас нет соответствующих разрешений для доступа к магазину плагинов.", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {плагин} few {плагина} other {плагинов}} из {total, number}", "marketplace_modal.install_plugins": "Установить плагины", "marketplace_modal.installing": "Устанавливается...", "marketplace_modal.list.configure": "Конфигурация", @@ -4965,11 +4963,7 @@ "start_trial.modal.gettingTrial": "Получение пробной версии...", "start_trial.modal.loaded": "Загружено!", "start_trial.modal.loading": "Загрузка...", - "start_trial.modal_body": "Получите доступ ко всем функциям платформы, включая расширенную безопасность и соответствие требованиям предприятия.", - "start_trial.modal_btn.nottnow": "Не сейчас", - "start_trial.modal_btn.start": "Начать бесплатную 30-дневную пробную версию", "start_trial.modal_btn.start_free_trial": "Начать бесплатную 30-дневную пробную версию", - "start_trial.modal_title": "Начните бесплатную пробную версию Enterprise прямо сейчас", "start_trial.tutorialTip.desc": "Изучите наши самые востребованные премиум-функции. Определяйте доступ пользователей с помощью гостевых учетных записей, автоматизируйте отчеты о соответствии и отправляйте мобильные push-уведомления только с безопасным идентификатором.", "start_trial.tutorialTip.title": "Попробуйте наши премиум-функции бесплатно", "status_dropdown.dnd_sub_menu_header": "Отключить уведомления до:", diff --git a/webapp/channels/src/i18n/sv.json b/webapp/channels/src/i18n/sv.json index 0bbb1aae3f..f459c90ff3 100644 --- a/webapp/channels/src/i18n/sv.json +++ b/webapp/channels/src/i18n/sv.json @@ -2647,7 +2647,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} raderade kanalens syfte (var tidigare {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} uppdaterat kanal syfte från: {old} till: {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} ändrade kanalens rubrik till: {new}", - "app.plugin.marketplace_plugins.app_error": "Fel vid anslutning till marketplace server. Kontrollera inställningarna i [System Console]({siteURL}/admin_console/plugins/plugin_management).", "app_bar.marketplace": "App Marketplace", "apps.error": "Fel: {error}", "apps.error.command.field_missing": "Nödvändiga fält saknas: `{fieldName}`.", @@ -4081,7 +4080,6 @@ "mark_all_threads_as_read_modal.title": "Markera alla dina trådar som lästa?", "marketplace_command.disabled": "Marknadsplatsen är inaktiverad. Kontakta din systemadministratör för mer information.", "marketplace_command.no_permission": "Du har inte rätt behörighet att komma åt marknadsplatsen.", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {plugin} other {plugins}} av totalt {total, number}", "marketplace_modal.install_plugins": "Installera plugins", "marketplace_modal.installing": "Installerar...", "marketplace_modal.list.configure": "Konfigurera", @@ -4973,11 +4971,7 @@ "start_trial.modal.gettingTrial": "Hämtar prova-på-period...", "start_trial.modal.loaded": "Laddad!", "start_trial.modal.loading": "Laddar...", - "start_trial.modal_body": "Få tillgång till alla funktioner inklusive avancerad säkerhet och efterlevnadskontroll för företags.", - "start_trial.modal_btn.nottnow": "Inte nu", - "start_trial.modal_btn.start": "Starta en kostnadsfri 30-dagars prova-på-period", "start_trial.modal_btn.start_free_trial": "Starta en kostnadsfri 30-dagars prova-på-period", - "start_trial.modal_title": "Starta din kostnadsfria prova-på-period för Enterprise nu", "start_trial.tutorialTip.desc": "Utforska våra mest efterfrågade premiumfunktioner. Bestäm användarnas åtkomst med gästkonton, automatisera rapporter om efterlevnad och skicka informationsskyddade notifieringar till mobilen.", "start_trial.tutorialTip.title": "Testa våra premiumfunktioner gratis", "status_dropdown.dnd_sub_menu_header": "Inaktivera notifieringar till:", diff --git a/webapp/channels/src/i18n/tr.json b/webapp/channels/src/i18n/tr.json index 6d3f2eb02d..366365b7a2 100644 --- a/webapp/channels/src/i18n/tr.json +++ b/webapp/channels/src/i18n/tr.json @@ -2605,7 +2605,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} kanal amacını kaldırdı (önceki: {old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username}, {old} eski kanal amacını {new} olarak değiştirdi", "app.channel.post_update_channel_purpose_message.updated_to": "{username} kanal amacını {new} olarak güncelledi", - "app.plugin.marketplace_plugins.app_error": "Mağaza sunucusu ile bağlantı kurulurken sorun çıktı. Lütfen [Sistem panosu]({siteURL}/admin_console/plugins/plugin_management) üzerinden ayarlarınızı denetleyin.", "apps.error": "Hata: {error}", "apps.error.command.field_missing": "Zorunlu alan eksik: `{fieldName}`.", "apps.error.command.same_channel": "`{fieldName}`alanında kanal yineleniyor: `{option}`.", @@ -4018,7 +4017,6 @@ "mark_all_threads_as_read_modal.title": "Tüm konularınız okunmuş olarak işaretlensin mi?", "marketplace_command.disabled": "Mağaza devre dışı bırakılmış. Lütfen ayrıntılı bilgi almak için sistem yöneticiniz ile görüşün.", "marketplace_command.no_permission": "Mağazaya erişmek için yeterli izinleriniz yok.", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {total, plural, one {uygulama eki} other {uygulama eki}} / {total, number}", "marketplace_modal.install_plugins": "Uygulama ekleri kur", "marketplace_modal.installing": "Kuruluyor...", "marketplace_modal.list.configure": "Yapılandır", @@ -4866,11 +4864,7 @@ "start_trial.modal.gettingTrial": "Deneme sürümü alınıyor...", "start_trial.modal.loaded": "Yüklendi!", "start_trial.modal.loading": "Yükleniyor...", - "start_trial.modal_body": "Gelişmiş güvenlik ve kurumsal uyumluluk ile tüm platform özelliklerine erişin.", - "start_trial.modal_btn.nottnow": "Şimdi değil", - "start_trial.modal_btn.start": "30 günlük ücretsiz denemeyi başlat", "start_trial.modal_btn.start_free_trial": "30 günlük ücretsiz denemeyi başlat", - "start_trial.modal_title": "Ücretsiz Enterprise tarifesi deneme sürenizi başlatın", "start_trial.tutorialTip.desc": "En çok istenilen ücretli özelliklerimizi keşfedin. Konuk hesapları ile kullanıcı erişimini sınırlayın, uyumluluk raporlarını otomatikleştirin ve yalnızca kimliğe özel güvenli mobil anında iletileri gönderin.", "start_trial.tutorialTip.title": "Ücretli özelliklerimizi ücretsiz olarak deneyin", "status_dropdown.dnd_sub_menu_header": "Bildirimler şu zamana kadar kapatılsın:", diff --git a/webapp/channels/src/i18n/uk.json b/webapp/channels/src/i18n/uk.json index a0195952b3..20abccf1f8 100644 --- a/webapp/channels/src/i18n/uk.json +++ b/webapp/channels/src/i18n/uk.json @@ -2192,7 +2192,6 @@ "login.verified": "Електронну пошту підтверджено", "login_mfa.submit": "Відправити", "login_mfa.token": "Токен MFA", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {count, plural, one {user} other {users}} of {total, number} total", "marketplace_modal.install_plugins": "Встановлені плагіни:", "marketplace_modal.list.try_again": "Спробуй ще раз ", "marketplace_modal.list.update": "Оновити", diff --git a/webapp/channels/src/i18n/zh-CN.json b/webapp/channels/src/i18n/zh-CN.json index 4672c79469..01bf58512a 100644 --- a/webapp/channels/src/i18n/zh-CN.json +++ b/webapp/channels/src/i18n/zh-CN.json @@ -2469,7 +2469,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} 移除了频道作用 (曾是:{old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} 更新了频道作用从:{old} 到:{new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} 更新了频道作用到:{new}", - "app.plugin.marketplace_plugins.app_error": "连接到集市服务器出错。请检查[系统控制台]({siteURL}/admin_console/plugins/plugin_management)的设定。", "apps.error": "错误:{error}", "apps.error.command.field_missing": "缺少必填字段:`{fieldName}`。", "apps.error.command.same_channel": "频道重复,字段 `{fieldName}`:`{option}`。", @@ -3567,7 +3566,6 @@ "manage_channel_groups_modal.search_placeholder": "搜索组", "manage_team_groups_modal.search_placeholder": "搜索组", "mark_all_threads_as_read_modal.cancel": "取消", - "marketplace_list.count_total_page": "{startCount, number} - {endCount, number} {count} 个,共 {total, number} 个", "marketplace_modal.install_plugins": "安装插件", "marketplace_modal.installing": "安装中...", "marketplace_modal.list.configure": "配置", @@ -4085,9 +4083,6 @@ "start_trial.modal.failed": "失败", "start_trial.modal.loaded": "已加载!", "start_trial.modal.loading": "加载中...", - "start_trial.modal_btn.nottnow": "现在不要", - "start_trial.modal_btn.start": "开始 30 天试用", - "start_trial.modal_title": "立即开始您的免费企业版试用", "status_dropdown.dnd_sub_menu_header": "禁用通知,直到:", "status_dropdown.dnd_sub_menu_item.custom": "自定义", "status_dropdown.dnd_sub_menu_item.one_hour": "1 小时", diff --git a/webapp/channels/src/i18n/zh-TW.json b/webapp/channels/src/i18n/zh-TW.json index 3d61e2d5b0..423beece99 100644 --- a/webapp/channels/src/i18n/zh-TW.json +++ b/webapp/channels/src/i18n/zh-TW.json @@ -1928,7 +1928,6 @@ "app.channel.post_update_channel_purpose_message.removed": "{username} 已移除頻道用途(原為:{old})", "app.channel.post_update_channel_purpose_message.updated_from": "{username} 已更新頻道用途:從 {old} 改為 {new}", "app.channel.post_update_channel_purpose_message.updated_to": "{username} 已更新頻道用途為:{new}", - "app.plugin.marketplace_plugins.app_error": "連線至市集伺服器失敗。請檢查[系統控制台]({siteURL}/admin_console/plugins/plugin_management)的設定。", "apps.error": "錯誤:{error}", "apps.error.command.field_missing": "遺漏必填欄位:`{fieldName}`。", "apps.error.command.same_channel": "頻道重複的欄位 `{fieldName}`:`{option}`。", @@ -2847,7 +2846,6 @@ "login_mfa.token": "多重要素驗證 Token", "manage_channel_groups_modal.search_placeholder": "搜尋群組", "manage_team_groups_modal.search_placeholder": "搜尋群組", - "marketplace_list.count_total_page": "{total, number}位中{startCount, number} - {endCount, number}位使用者", "marketplace_modal.install_plugins": "安裝模組", "marketplace_modal.installing": "安裝中...", "marketplace_modal.list.configure": "設定", From 0d6b3576d5e24c35c9066719fe8d3d69ed9e1cc4 Mon Sep 17 00:00:00 2001 From: Felipe Nogueira Date: Tue, 4 Apr 2023 09:37:24 +0200 Subject: [PATCH 33/58] Translated using Weblate (Portuguese (Brazil)) Currently translated at 71.1% (4103 of 5766 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/pt_BR/ --- webapp/channels/src/i18n/pt-BR.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/webapp/channels/src/i18n/pt-BR.json b/webapp/channels/src/i18n/pt-BR.json index 6e21aa2a99..e63417119f 100644 --- a/webapp/channels/src/i18n/pt-BR.json +++ b/webapp/channels/src/i18n/pt-BR.json @@ -25,6 +25,8 @@ "accessibility.button.Info": "Informações", "accessibility.button.Search": "Procurar", "accessibility.button.attachment": "anexo", + "accessibility.button.bold": "negrito", + "accessibility.button.code": "código", "accessibility.button.dialog": "Diálogo {dialogName}", "accessibility.button.italic": "itálico", "accessibility.button.numbered_list": "lista numerada", @@ -247,6 +249,7 @@ "admin.billing.history.fractionalAndRatedUsers": "{fractionalUsers} usuários medidos, {fullUsers} usuários com taxa total, {partialUsers} usuários com cobranças parciais", "admin.billing.history.fractionalUsers": "{fractionalUsers} usuários", "admin.billing.history.noBillingHistory": "No futuro, é aqui que seu histórico de faturamento será exibido.", + "admin.billing.history.onPremUsers": "{num} usuários", "admin.billing.history.pageInfo": "{startRecord} - {endRecord} de {totalRecords}", "admin.billing.history.paid": "Pago", "admin.billing.history.paymentFailed": "Pagamento falhou", @@ -280,6 +283,7 @@ "admin.billing.subscription.cancelSubscriptionSection.contactUs": "Contate-Nos", "admin.billing.subscription.cancelSubscriptionSection.description": "No momento, a exclusão de um espaço de trabalho só pode ser feita com a ajuda de um representante de suporte ao cliente.", "admin.billing.subscription.cancelSubscriptionSection.title": "Cancelar sua assinatura", + "admin.billing.subscription.cloudMonthlyBadge": "Mensalmente", "admin.billing.subscription.creditCardExpired": "Seu cartão de crédito expirou. Atualize suas informações de pagamento para evitar interrupções.", "admin.billing.subscription.creditCardHasExpired": "Seu cartão de crédito expirou", "admin.billing.subscription.goBackTryAgain": "Volte e tente novamente", From cabd3c4b7e50786c40696c5c2974abc607649076 Mon Sep 17 00:00:00 2001 From: "Maxime tremblay Godindustry@gmail.com" Date: Tue, 4 Apr 2023 09:37:25 +0200 Subject: [PATCH 34/58] Translated using Weblate (French) Currently translated at 84.6% (4879 of 5766 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/fr/ --- webapp/channels/src/i18n/fr.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/webapp/channels/src/i18n/fr.json b/webapp/channels/src/i18n/fr.json index f499e597dc..27f84b505c 100644 --- a/webapp/channels/src/i18n/fr.json +++ b/webapp/channels/src/i18n/fr.json @@ -3064,7 +3064,7 @@ "edit_post.time_limit_modal.subscript": "Définit la durée durant laquelle les utilisateurs pourront modifier leur message après l'avoir envoyé.", "edit_post.time_limit_modal.title": "Configurer le délai global d'édition de messages", "email_verify.almost": "Vous avez pratiquement terminé !", - "email_verify.failed": " Échec de l'envoi de l'e-mail de vérification.", + "email_verify.failed": "Maxtrem271991@gmail.com", "email_verify.notVerifiedBody": "Veuillez vérifier votre adresse e-mail dans l'attente de la réception d'un e-mail de vérification.", "email_verify.resend": "Renvoyer l'e-mail", "email_verify.sent": " L'e-mail de vérification a été envoyé.", @@ -4874,6 +4874,8 @@ "web.header.back": "Précédent", "web.header.logout": "Se déconnecter", "web.root.signup_info": "Toute la communication de votre équipe au même endroit, accessible de partout", + "welcome_post_renderer.user_message.first_paragraph": "Mattermost is an open source platform for secure communication, collaboration, and orchestration of work across tools and teams.", + "welcome_post_renderer.user_message.title": "\t ", "widget.input.required": "Ce champ est requis", "widgets.channels_input.empty": "Aucun canal trouvé", "widgets.channels_input.loading": "Chargement", From 70a97de2257c3ae1dd7ceab3348cc7b17e195aa1 Mon Sep 17 00:00:00 2001 From: jprusch Date: Tue, 4 Apr 2023 09:37:25 +0200 Subject: [PATCH 35/58] Translated using Weblate (German) Currently translated at 100.0% (5770 of 5770 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/de/ Translated using Weblate (German) Currently translated at 100.0% (5766 of 5766 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/de/ --- webapp/channels/src/i18n/de.json | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/webapp/channels/src/i18n/de.json b/webapp/channels/src/i18n/de.json index f1839cf072..7d29a4fe4f 100644 --- a/webapp/channels/src/i18n/de.json +++ b/webapp/channels/src/i18n/de.json @@ -3440,6 +3440,9 @@ "filtered_user_list.userStatus": "Benutzerstatus:", "flag_post.flag": "Zur Nachverfolgung markieren", "flag_post.unflag": "Markierung entfernen", + "footer_pagination.count": "Zeige {startCount, number}-{endCount, number} von {total, number}", + "footer_pagination.next": "Weiter", + "footer_pagination.prev": "Zurück", "forward_post_button.label": "Weiterleiten", "forward_post_modal.button.cancel": "Abbrechen", "forward_post_modal.button.forward": "Weiterleiten", @@ -4084,6 +4087,7 @@ "mark_all_threads_as_read_modal.title": "Alle deine Unterhaltungen als gelesen markieren?", "marketplace_command.disabled": "Der Marktplatz ist deaktiviert. Bitte kontaktiere deinen Systemadmin für Details.", "marketplace_command.no_permission": "Du hast nicht die erforderlichen Berechtigungen um auf den Marktplatz zuzugreifen.", + "marketplace_modal.app_error": "Fehler beim Verbinden mit dem Marktplatz-Server. Bitte überprüfe deine Einstellungen in der Systemkonsole.", "marketplace_modal.install_plugins": "Plugins installieren", "marketplace_modal.installing": "Installiere...", "marketplace_modal.list.configure": "Konfigurieren", @@ -4101,12 +4105,13 @@ "marketplace_modal.list.update_confirmation.message.warning_major_version": "Dieses Update kann inkompatible Änderungen enthalten.", "marketplace_modal.list.update_confirmation.message.warning_major_version_with_release_notes": "Dieses Update kann inkompatible Änderungen enthalten. Prüfe die [Release Notes](!{releaseNotesUrl}) vor dem Upgrade.", "marketplace_modal.list.update_confirmation.title": "Plugin-Update bestätigen", - "marketplace_modal.no_plugins": "Zurzeit sind keine Plugins verfügbar.", - "marketplace_modal.no_plugins_installed": "Du hast keine Plugins installiert.", - "marketplace_modal.search": "Plugin-Marktplatz durchsuchen", + "marketplace_modal.no_plugins": "Keine Plugins gefunden", + "marketplace_modal.no_plugins_installed": "Keine installierten Plugins gefunden", + "marketplace_modal.search": "Marktplatz durchsuchen", "marketplace_modal.tabs.all_listing": "Alle", - "marketplace_modal.tabs.installed_listing": "Installierte", - "marketplace_modal.title": "Plugin-Marktplatz", + "marketplace_modal.tabs.installed_listing": "Installiert ({count})", + "marketplace_modal.title": "App-Marktplatz", + "marketplace_modal_list.no_plugins_filter": "Keine Ergebnisse für \"{filter}\"", "members_popover.button.message": "Nachricht", "menu.cloudFree.enterpriseTrialDescription": "Dein Test ist aktiv bis zum {trialEndDay}. Entdecke unsere besten Enterprise Funktionen. Erfahre mehr", "menu.cloudFree.enterpriseTrialTitle": "Enterprise Test", @@ -4287,6 +4292,7 @@ "onboardingTask.checklist.downloads": "Jetzt, da du alles konfiguriert hast, lade unsere Apps runter.", "onboardingTask.checklist.higher_security_features": "Interessiert an unseren Hochsicherheitsfunktionen?", "onboardingTask.checklist.main_subtitle": "Legen wir los.", + "onboardingTask.checklist.no_thanks": "Nein, danke", "onboardingTask.checklist.start_enterprise_now": "Starte jetzt Deinen kostenfreien Enterprise-Test!", "onboardingTask.checklist.task_complete_your_profile": "Vervollständige dein Profil.", "onboardingTask.checklist.task_create_from_work_template": "Erstellen aus einer Vorlage", @@ -5673,6 +5679,7 @@ "welcome_post_renderer.user_message.first_paragraph": "Mattermost ist eine Open-Source-Plattform für sichere Kommunikation, Zusammenarbeit und Orchestrierung der Arbeit über Tools und Teams hinweg.", "welcome_post_renderer.user_message.second_paragraph": "Hier findest Du eine Liste von Befehlen, die Du verwenden kannst, um sich mit der Plattform vertraut zu machen.", "welcome_post_renderer.user_message.title": "Willkommen bei Mattermost! :rocket:", + "widget.input.clear": "Leeren", "widget.input.required": "Dieses Feld wird benötigt", "widget.passwordInput.createPassword": "Wähle ein Passwort", "widget.passwordInput.password": "Passwort", From 8ccf5c3c143ccc5774dd9b73f9d629a8d6f18948 Mon Sep 17 00:00:00 2001 From: master7 Date: Tue, 4 Apr 2023 09:37:26 +0200 Subject: [PATCH 36/58] Translated using Weblate (Polish) Currently translated at 99.7% (5756 of 5770 strings) Translation: mattermost-languages-shipped/mattermost-webapp-monorepo Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp-monorepo/pl/ --- webapp/channels/src/i18n/pl.json | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/webapp/channels/src/i18n/pl.json b/webapp/channels/src/i18n/pl.json index 09434f4323..3e6612a6a6 100644 --- a/webapp/channels/src/i18n/pl.json +++ b/webapp/channels/src/i18n/pl.json @@ -1339,6 +1339,7 @@ "admin.license.title": "Edycja i licencja", "admin.license.trial-request.accept-terms": "Klikając Rozpocznij wersję próbną, wyrażam zgodę na Mattermost Software and Services License Agreement, Privacy Policy oraz na otrzymywanie wiadomości e-mail dotyczących produktu.", "admin.license.trial-request.embargoed": "Nie mogliśmy przetworzyć tego żądania z powodu ograniczeń dotyczących krajów objętych embargiem. Dowiedz się więcej w naszej dokumentacji lub wyślij wiadomość na adres legal@mattermost.com, aby uzyskać odpowiedzi na pytania dotyczące ograniczeń eksportowych.", + "admin.license.trial-request.embargoed.button": "Zamknij", "admin.license.trial-request.startTrial": "Rozpoczęcie wersji trial", "admin.license.trial-request.title": "Korzystaj z Mattermost Enterprise Edition za darmo przez następne 30 dni. Nie ma obowiązku zakupu lub karty kredytowej. ", "admin.license.trialCard.contactSales": "Kontakt ze sprzedażą", @@ -2562,6 +2563,9 @@ "admin.webserverModeUncompressed": "Nieskompresowany", "admin.webserverModeUncompressedDescription": "Serwer Mattermost będzie serwował nieskompresowane statyczne pliki.", "admin_settings.save_unsaved_changes": "Należy najpierw zapisać niezapisane zmiany", + "air_gapped_modal.close": "Zamknij", + "air_gapped_modal.description": "Aby uruchomić wersję próbną, odwiedź stronę {link} i poproś o klucz próbny.", + "air_gapped_modal.title": "Poproś o klucz próbny", "alert_banner.tooltipCloseBtn": "Zamknij", "analytics.chart.loading": "Ładowanie...", "analytics.chart.meaningful": "Za mało danych dla sensownej reprezentacji.", @@ -3436,6 +3440,9 @@ "filtered_user_list.userStatus": "Status użytkownika:", "flag_post.flag": "Oznacz do obserwacji", "flag_post.unflag": "Usuń flagę", + "footer_pagination.count": "Pokazuje{startCount, number}-{endCount, number} z {total, number}", + "footer_pagination.next": "Dalej", + "footer_pagination.prev": "Wstecz", "forward_post_button.label": "Przekaż", "forward_post_modal.button.cancel": "Anuluj", "forward_post_modal.button.forward": "Przekaż", @@ -4080,7 +4087,8 @@ "mark_all_threads_as_read_modal.title": "Oznaczyć wszystkie twoje wątki jako przeczytane?", "marketplace_command.disabled": "Sklep jest wyłączony. W celu uzyskania szczegółowych informacji należy skontaktować się z administratorem systemu.", "marketplace_command.no_permission": "Nie masz odpowiednich uprawnień, aby uzyskać dostęp do sklepu.", - "marketplace_modal.install_plugins": "Zainstaluj wtyczki", + "marketplace_modal.app_error": "Błąd połączenia z serwerem marketplace. Proszę sprawdzić swoje ustawienia w Konsoli Systemowej .", + "marketplace_modal.install_plugins": "Zainstaluj Wtyczki", "marketplace_modal.installing": "Instalowanie...", "marketplace_modal.list.configure": "Konfiguruj", "marketplace_modal.list.configure.plugin": "Skonfiguruj {plugin}", @@ -4097,12 +4105,13 @@ "marketplace_modal.list.update_confirmation.message.warning_major_version": "Ta aktualizacja może zawierać duże zmiany.", "marketplace_modal.list.update_confirmation.message.warning_major_version_with_release_notes": "Ta aktualizacja może zawierać duże zmiany. Przejrzyj [release notes](!{releaseNotesUrl}) przed aktualizacją.", "marketplace_modal.list.update_confirmation.title": "Potwierdź aktualizację wtyczki", - "marketplace_modal.no_plugins": "Obecnie nie ma dostępnych wtyczek.", + "marketplace_modal.no_plugins": "Nie znaleziono żadnych wtyczek", "marketplace_modal.no_plugins_installed": "Nie masz zainstalowanych żadnych wtyczek.", - "marketplace_modal.search": "Szukaj w Sklepie", + "marketplace_modal.search": "Szukaj w sklepie", "marketplace_modal.tabs.all_listing": "Wszystko", - "marketplace_modal.tabs.installed_listing": "Zainstalowane", - "marketplace_modal.title": "Sklep", + "marketplace_modal.tabs.installed_listing": "Zainstalowane ({count})", + "marketplace_modal.title": "Sklep z Aplikacjami", + "marketplace_modal_list.no_plugins_filter": "Brak wyników dla \"{filter}\"", "members_popover.button.message": "wiadomość", "menu.cloudFree.enterpriseTrialDescription": "Twój okres próbny jest aktywny do {trialEndDay}. Poznaj nasze najważniejsze funkcje Enterprise. Dowiedz się więcej", "menu.cloudFree.enterpriseTrialTitle": "Enterprise Trial", @@ -4283,9 +4292,10 @@ "onboardingTask.checklist.downloads": "Teraz, gdy wszystko jest już gotowe, pobierz nasze aplikacje", "onboardingTask.checklist.higher_security_features": "Interesują Cię nasze funkcje o podwyższonym poziomie bezpieczeństwa?", "onboardingTask.checklist.main_subtitle": "Zaczynamy i działamy.", + "onboardingTask.checklist.no_thanks": "Nie, dzięki", "onboardingTask.checklist.start_enterprise_now": "Rozpocznij bezpłatny okres próbny Enterprise już teraz!", "onboardingTask.checklist.task_complete_your_profile": "Uzupełnij swój profil.", - "onboardingTask.checklist.task_create_from_work_template": "Utwórz z szablonu - ustaw kanał z połączonymi tablicami i playbookami.", + "onboardingTask.checklist.task_create_from_work_template": "Utwórz z szablonu", "onboardingTask.checklist.task_download_mm_apps": "Pobierz aplikację desktopową i mobilną.", "onboardingTask.checklist.task_explore_other_tools_in_platform": "Poznaj inne narzędzia w platformie.", "onboardingTask.checklist.task_invite_team_members": "Zaproś członków zespołu do obszaru roboczego.", @@ -4857,7 +4867,7 @@ "sidebar.directchannel.you": "{displayname} (ty)", "sidebar.menu.item.notSelected": "nie wybrany", "sidebar.menu.item.selected": "wybrane", - "sidebar.openDirectMessage": "Otwórz Wiadomość Bezpośrednią", + "sidebar.openDirectMessage": "Otwórz wiadomość bezpośrednią", "sidebar.show": "Pokaż", "sidebar.sort": "Sortuj", "sidebar.sortedByRecencyLabel": "Ostatnia aktywność", @@ -4874,15 +4884,15 @@ "sidebar.unreads": "Więcej nieprzeczytanych", "sidebar_left.addChannelsCta": "Dodaj kanały", "sidebar_left.add_channel_cta_dropdown.dropdownAriaLabel": "Dodaj Menu Rozwijane Kanału", - "sidebar_left.add_channel_dropdown.browseChannels": "Przeglądaj Kanały", + "sidebar_left.add_channel_dropdown.browseChannels": "Przeglądaj kanały", "sidebar_left.add_channel_dropdown.browseOrCreateChannels": "Przeglądaj lub twórz kanały", "sidebar_left.add_channel_dropdown.createCategory": "Utwórz nową kategorię", - "sidebar_left.add_channel_dropdown.createNewChannel": "Utwórz Nowy Kanał", + "sidebar_left.add_channel_dropdown.createNewChannel": "Utwórz nowy kanał", "sidebar_left.add_channel_dropdown.dropdownAriaLabel": "Dodaj Menu Rozwijane Kanału", - "sidebar_left.add_channel_dropdown.invitePeople": "Zaproś Ludzi", + "sidebar_left.add_channel_dropdown.invitePeople": "Zaproś osoby", "sidebar_left.add_channel_dropdown.invitePeopleExtraText": "Dodaj ludzi do zespołu", "sidebar_left.add_channel_dropdown.work_template": "Utwórz z szablonu", - "sidebar_left.add_channel_dropdown.work_template_extra": "Skonfiguruj kanał z połączonymi tablicami i playbookami", + "sidebar_left.add_channel_dropdown.work_template_extra": "Połącz razem kanały, tablice i playbooki", "sidebar_left.channel_filter.filterByUnread": "Filtruj według nieprzeczytanych", "sidebar_left.channel_filter.filterUnreadAria": "filtr nieprzeczytanych", "sidebar_left.channel_filter.showAllChannels": "Pokaż wszystkie kanały", From 3d8701058ab9cec75dc10bece8b4fdd2c6e0112a Mon Sep 17 00:00:00 2001 From: Ashish Dhama <16203333+AshishDhama@users.noreply.github.com> Date: Tue, 4 Apr 2023 15:03:04 +0530 Subject: [PATCH 37/58] adding aria-live to resolve JAWS issue (#22785) Co-authored-by: Babinder Rathi babinderrathi@gmail.com --- webapp/channels/src/components/invitation_modal/invite_view.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/channels/src/components/invitation_modal/invite_view.tsx b/webapp/channels/src/components/invitation_modal/invite_view.tsx index 9d6ec6292a..298171db63 100644 --- a/webapp/channels/src/components/invitation_modal/invite_view.tsx +++ b/webapp/channels/src/components/invitation_modal/invite_view.tsx @@ -102,6 +102,7 @@ export default function InviteView(props: Props) { }, {inviteURL}) } className='InviteView__copyLink' + aria-live='polite' > {!copyText.copiedRecently && ( <> From bbadbfde45403fc4844867359c1b71933d7317b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Tue, 4 Apr 2023 11:39:40 +0200 Subject: [PATCH 38/58] MM-51912 - fix not able to scroll in the LHS (#22806) --- .../sidebar_list/__snapshots__/sidebar_list.test.tsx.snap | 1 - .../src/components/sidebar/sidebar_list/sidebar_list.tsx | 2 +- webapp/channels/src/sass/layout/_sidebar-left.scss | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/webapp/channels/src/components/sidebar/sidebar_list/__snapshots__/sidebar_list.test.tsx.snap b/webapp/channels/src/components/sidebar/sidebar_list/__snapshots__/sidebar_list.test.tsx.snap index 1c5fcb8bd6..a3c08318c4 100644 --- a/webapp/channels/src/components/sidebar/sidebar_list/__snapshots__/sidebar_list.test.tsx.snap +++ b/webapp/channels/src/components/sidebar/sidebar_list/__snapshots__/sidebar_list.test.tsx.snap @@ -54,7 +54,6 @@ exports[`SidebarList should match snapshot 1`] = ` renderView={[Function]} style={ Object { - "overflow": "initial", "position": "absolute", } } diff --git a/webapp/channels/src/components/sidebar/sidebar_list/sidebar_list.tsx b/webapp/channels/src/components/sidebar/sidebar_list/sidebar_list.tsx index d6cf96dab2..88b5fd989f 100644 --- a/webapp/channels/src/components/sidebar/sidebar_list/sidebar_list.tsx +++ b/webapp/channels/src/components/sidebar/sidebar_list/sidebar_list.tsx @@ -69,7 +69,7 @@ export function renderThumbVertical(props: any) { ); } -const scrollbarStyles: CSSProperties = {position: 'absolute', overflow: 'initial'}; +const scrollbarStyles: CSSProperties = {position: 'absolute'}; type Props = { currentTeam: Team; diff --git a/webapp/channels/src/sass/layout/_sidebar-left.scss b/webapp/channels/src/sass/layout/_sidebar-left.scss index 9193927337..2f5aa4759a 100644 --- a/webapp/channels/src/sass/layout/_sidebar-left.scss +++ b/webapp/channels/src/sass/layout/_sidebar-left.scss @@ -578,7 +578,6 @@ $sidebarOpacityAnimationDuration: 0.15s; @media screen and (min-width: 768px) { .SidebarNavContainer { .scrollbar--view { - overflow: initial !important; max-width: 240px; } } @@ -754,7 +753,7 @@ $sidebarOpacityAnimationDuration: 0.15s; } .AddChannelsCtaDropdown .dropdown-menu { - min-width: 232px !important; + min-width: 210px !important; margin-left: 20px; } From ed36e8bd645f78e08ac181e64d63dbd3ad6b23dc Mon Sep 17 00:00:00 2001 From: Allan Guwatudde Date: Tue, 4 Apr 2023 13:57:32 +0300 Subject: [PATCH 39/58] [MM-51236] - Add opt-in checkbox in self-hosted account creation page (#22709) * [MM-51236] - Add opt-in checkbox in self-hosted account creation page * add server impl * fix lint and translations * add tests * improvents * fix model * fix mocks * feedback impl * update text color * handle error * fix tests --- model/hosted_customer.go | 6 ++ server/channels/api4/hosted_customer.go | 32 ++++++++ server/channels/einterfaces/cloud.go | 1 + .../einterfaces/mocks/CloudInterface.go | 14 ++++ server/i18n/en.json | 4 + .../signup/__snapshots__/signup.test.tsx.snap | 44 +++++++++++ .../src/components/signup/signup.scss | 16 ++++ .../src/components/signup/signup.test.tsx | 51 +++++++++++- .../channels/src/components/signup/signup.tsx | 78 ++++++++++++++++++- .../widgets/inputs/check/check.scss | 19 +++++ .../components/widgets/inputs/check/index.tsx | 28 +++++++ webapp/channels/src/i18n/en.json | 3 + webapp/channels/src/utils/constants.tsx | 1 + webapp/platform/client/src/client4.ts | 8 ++ webapp/platform/types/src/cloud.ts | 5 ++ 15 files changed, 304 insertions(+), 6 deletions(-) create mode 100644 webapp/channels/src/components/widgets/inputs/check/check.scss create mode 100644 webapp/channels/src/components/widgets/inputs/check/index.tsx diff --git a/model/hosted_customer.go b/model/hosted_customer.go index 543ea12b74..608892e5e5 100644 --- a/model/hosted_customer.go +++ b/model/hosted_customer.go @@ -8,6 +8,12 @@ type BootstrapSelfHostedSignupRequest struct { Reset bool `json:"reset"` } +type SubscribeNewsletterRequest struct { + Email string `json:"email"` + ServerID string `json:"server_id"` + SubscribedContent string `json:"subscribed_content"` +} + type BootstrapSelfHostedSignupResponse struct { Progress string `json:"progress"` // email listed on the JWT claim diff --git a/server/channels/api4/hosted_customer.go b/server/channels/api4/hosted_customer.go index bbed311ea4..ba791c28cc 100644 --- a/server/channels/api4/hosted_customer.go +++ b/server/channels/api4/hosted_customer.go @@ -36,6 +36,8 @@ func (api *API) InitHostedCustomer() { api.BaseRoutes.HostedCustomer.Handle("/invoices", api.APISessionRequired(selfHostedInvoices)).Methods("GET") // GET /api/v4/hosted_customer/invoices/{invoice_id:in_[A-Za-z0-9]+}/pdf api.BaseRoutes.HostedCustomer.Handle("/invoices/{invoice_id:in_[A-Za-z0-9]+}/pdf", api.APISessionRequired(selfHostedInvoicePDF)).Methods("GET") + + api.BaseRoutes.HostedCustomer.Handle("/subscribe-newsletter", api.APIHandler(handleSubscribeToNewsletter)).Methods(http.MethodPost) } func ensureSelfHostedAdmin(c *Context, where string) { @@ -293,3 +295,33 @@ func selfHostedInvoicePDF(c *Context, w http.ResponseWriter, r *http.Request) { r, ) } + +func handleSubscribeToNewsletter(c *Context, w http.ResponseWriter, r *http.Request) { + const where = "Api4.handleSubscribeToNewsletter" + ensured := ensureCloudInterface(c, where) + if !ensured { + return + } + + bodyBytes, err := io.ReadAll(r.Body) + if err != nil { + c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusBadRequest).Wrap(err) + return + } + + req := new(model.SubscribeNewsletterRequest) + err = json.Unmarshal(bodyBytes, req) + if err != nil { + c.Err = model.NewAppError(where, "api.cloud.request_error", nil, "", http.StatusBadRequest).Wrap(err) + return + } + + req.ServerID = c.App.Srv().TelemetryId() + + if err := c.App.Cloud().SubscribeToNewsletter("", req); err != nil { + c.Err = model.NewAppError(where, "api.server.cws.subscribe_to_newsletter.app_error", nil, "CWS Server failed to subscribe to newsletter.", http.StatusInternalServerError).Wrap(err) + return + } + + ReturnStatusOK(w) +} diff --git a/server/channels/einterfaces/cloud.go b/server/channels/einterfaces/cloud.go index b5d6a75b68..70cdc4676a 100644 --- a/server/channels/einterfaces/cloud.go +++ b/server/channels/einterfaces/cloud.go @@ -47,4 +47,5 @@ type CloudInterface interface { CheckCWSConnection(userId string) error SelfServeDeleteWorkspace(userID string, deletionRequest *model.WorkspaceDeletionRequest) error + SubscribeToNewsletter(userID string, req *model.SubscribeNewsletterRequest) error } diff --git a/server/channels/einterfaces/mocks/CloudInterface.go b/server/channels/einterfaces/mocks/CloudInterface.go index db7c86acc2..2dd2711650 100644 --- a/server/channels/einterfaces/mocks/CloudInterface.go +++ b/server/channels/einterfaces/mocks/CloudInterface.go @@ -540,6 +540,20 @@ func (_m *CloudInterface) SelfServeDeleteWorkspace(userID string, deletionReques return r0 } +// SubscribeToNewsletter provides a mock function with given fields: userID, req +func (_m *CloudInterface) SubscribeToNewsletter(userID string, req *model.SubscribeNewsletterRequest) error { + ret := _m.Called(userID, req) + + var r0 error + if rf, ok := ret.Get(0).(func(string, *model.SubscribeNewsletterRequest) error); ok { + r0 = rf(userID, req) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // UpdateCloudCustomer provides a mock function with given fields: userID, customerInfo func (_m *CloudInterface) UpdateCloudCustomer(userID string, customerInfo *model.CloudCustomerInfo) (*model.CloudCustomer, error) { ret := _m.Called(userID, customerInfo) diff --git a/server/i18n/en.json b/server/i18n/en.json index 506628e0bb..e73fa524c8 100644 --- a/server/i18n/en.json +++ b/server/i18n/en.json @@ -2591,6 +2591,10 @@ "id": "api.server.cws.needs_enterprise_edition", "translation": "Service only available in Mattermost Enterprise edition" }, + { + "id": "api.server.cws.subscribe_to_newsletter.app_error", + "translation": "CWS Server failed to subscribe to newsletter." + }, { "id": "api.server.hosted_signup_unavailable.error", "translation": "Portal unavailable for self-hosted signup." diff --git a/webapp/channels/src/components/signup/__snapshots__/signup.test.tsx.snap b/webapp/channels/src/components/signup/__snapshots__/signup.test.tsx.snap index 691b7341e9..7ab9e4ee2c 100644 --- a/webapp/channels/src/components/signup/__snapshots__/signup.test.tsx.snap +++ b/webapp/channels/src/components/signup/__snapshots__/signup.test.tsx.snap @@ -93,6 +93,28 @@ exports[`components/signup/Signup should match snapshot for all signup options e onChange={[Function]} value="" /> +
    + + Interested in receiving Mattermost security updates via newsletter? + + + Sign up at + + https://mattermost.com/security-updates/ + + . + +
    +
    + + Interested in receiving Mattermost security updates via newsletter? + + + Sign up at + + https://mattermost.com/security-updates/ + + . + +
    ; let mockDispatch = jest.fn(); @@ -96,7 +98,7 @@ describe('components/signup/Signup', () => { beforeEach(() => { mockLocation = {pathname: '', search: '', hash: ''}; - mockLicense = {IsLicensed: 'true'}; + mockLicense = {IsLicensed: 'true', Cloud: 'false'}; mockState = { entities: { @@ -178,7 +180,7 @@ describe('components/signup/Signup', () => { }); it('should match snapshot for all signup options enabled with isLicensed disabled', () => { - mockLicense = {IsLicensed: 'false'}; + mockLicense = {IsLicensed: 'false', Cloud: 'false'}; const wrapper = shallow( , @@ -295,4 +297,45 @@ describe('components/signup/Signup', () => { expect(wrapper.find('.content-layout-column-title').text()).toEqual('This invite link is invalid'); }); }); + + it('should show newsletter check box opt-in for self-hosted non airgapped workspaces', async () => { + jest.spyOn(useCWSAvailabilityCheckAll, 'default').mockImplementation(() => true); + mockLicense = {IsLicensed: 'true', Cloud: 'false'}; + + const {container: signupContainer} = renderWithIntlAndStore( + + + , {}); + + screen.getByTestId('signup-body-card-form-check-newsletter'); + const checkInput = screen.getByTestId('signup-body-card-form-check-newsletter'); + expect(checkInput).toHaveAttribute('type', 'checkbox'); + + expect(signupContainer).toHaveTextContent(/I would like to receive Mattermost security updates via newsletter. Data Terms and Conditions apply/); + }); + + it('should NOT show newsletter check box opt-in for self-hosted AND airgapped workspaces', async () => { + jest.spyOn(useCWSAvailabilityCheckAll, 'default').mockImplementation(() => false); + mockLicense = {IsLicensed: 'true', Cloud: 'false'}; + + const {container: signupContainer} = renderWithIntlAndStore( + + + , {}); + + expect(() => screen.getByTestId('signup-body-card-form-check-newsletter')).toThrow(); + expect(signupContainer).toHaveTextContent('Interested in receiving Mattermost security updates via newsletter?Sign up at https://mattermost.com/security-updates/.'); + }); + + it('should not show any newsletter related opt-in or text for cloud', async () => { + jest.spyOn(useCWSAvailabilityCheckAll, 'default').mockImplementation(() => true); + mockLicense = {IsLicensed: 'true', Cloud: 'true'}; + + renderWithIntlAndStore( + + + , {}); + + expect(() => screen.getByTestId('signup-body-card-form-check-newsletter')).toThrow(); + }); }); diff --git a/webapp/channels/src/components/signup/signup.tsx b/webapp/channels/src/components/signup/signup.tsx index dde147597f..3f3a13d460 100644 --- a/webapp/channels/src/components/signup/signup.tsx +++ b/webapp/channels/src/components/signup/signup.tsx @@ -48,9 +48,12 @@ import LoginOpenIDIcon from 'components/widgets/icons/login_openid_icon'; import LoginOffice365Icon from 'components/widgets/icons/login_office_365_icon'; import Input, {CustomMessageInputType, SIZE} from 'components/widgets/inputs/input/input'; import PasswordInput from 'components/widgets/inputs/password_input/password_input'; +import CheckInput from 'components/widgets/inputs/check'; import SaveButton from 'components/save_button'; +import useCWSAvailabilityCheck from 'components/common/hooks/useCWSAvailabilityCheck'; +import ExternalLink from 'components/external_link'; -import {Constants, ItemStatus, ValidationErrors} from 'utils/constants'; +import {Constants, HostedCustomerLinks, ItemStatus, ValidationErrors} from 'utils/constants'; import {isValidUsername, isValidPassword, getPasswordConfig, getRoleFromTrackFlow, getMediumFromTrackFlow} from 'utils/utils'; import './signup.scss'; @@ -99,7 +102,7 @@ const Signup = ({onCustomizeHeader}: SignupProps) => { TermsOfServiceLink, PrivacyPolicyLink, } = config; - const {IsLicensed} = useSelector(getLicense); + const {IsLicensed, Cloud} = useSelector(getLicense); const loggedIn = Boolean(useSelector(getCurrentUserId)); const useCaseOnboarding = useSelector(getUseCaseOnboarding); const usedBefore = useSelector((state: GlobalState) => (!inviteId && !loggedIn && token ? getGlobalItem(state, token, null) : undefined)); @@ -110,6 +113,7 @@ const Signup = ({onCustomizeHeader}: SignupProps) => { const passwordInput = useRef(null); const isLicensed = IsLicensed === 'true'; + const isCloud = Cloud === 'true'; const enableOpenServer = EnableOpenServer === 'true'; const noAccounts = NoAccounts === 'true'; const enableSignUpWithEmail = EnableSignUpWithEmail === 'true'; @@ -136,12 +140,24 @@ const Signup = ({onCustomizeHeader}: SignupProps) => { const [teamName, setTeamName] = useState(parsedTeamName ?? ''); const [alertBanner, setAlertBanner] = useState(null); const [isMobileView, setIsMobileView] = useState(false); + const [subscribeToSecurityNewsletter, setSubscribeToSecurityNewsletter] = useState(false); + + const canReachCWS = useCWSAvailabilityCheck(); const enableExternalSignup = enableSignUpWithGitLab || enableSignUpWithOffice365 || enableSignUpWithGoogle || enableSignUpWithOpenId || enableLDAP || enableSAML; const hasError = Boolean(emailError || nameError || passwordError || serverError || alertBanner); const canSubmit = Boolean(email && name && password) && !hasError && !loading; const {error: passwordInfo} = isValidPassword('', getPasswordConfig(config), intl); + const subscribeToSecurityNewsletterFunc = () => { + try { + Client4.subscribeToNewsletter({email, subscribed_content: 'security_newsletter'}); + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + } + }; + const getExternalSignupOptions = () => { const externalLoginOptions: ExternalLoginButtonType[] = []; @@ -564,6 +580,9 @@ const Signup = ({onCustomizeHeader}: SignupProps) => { } await handleSignupSuccess(user, data as UserProfile); + if (subscribeToSecurityNewsletter) { + subscribeToSecurityNewsletterFunc(); + } } else { setIsWaiting(false); } @@ -571,6 +590,60 @@ const Signup = ({onCustomizeHeader}: SignupProps) => { const handleReturnButtonOnClick = () => history.replace('/'); + const getNewsletterCheck = () => { + if (isCloud) { + return null; + } + + if (canReachCWS) { + return ( + setSubscribeToSecurityNewsletter(!subscribeToSecurityNewsletter)} + text={ + formatMessage( + {id: 'newsletter_optin.checkmark.text', defaultMessage: 'I would like to receive Mattermost security updates via newsletter. Data Terms and Conditions apply'}, + { + a: (chunks: React.ReactNode | React.ReactNodeArray) => ( + + {chunks} + + ), + }, + )} + checked={subscribeToSecurityNewsletter} + /> + ); + } + return ( +
    + + {formatMessage({id: 'newsletter_optin.title', defaultMessage: 'Interested in receiving Mattermost security updates via newsletter?'})} + + + {formatMessage( + {id: 'newsletter_optin.desc', defaultMessage: 'Sign up at {link}.'}, + { + link: HostedCustomerLinks.SECURITY_UPDATES, + a: (chunks: React.ReactNode | React.ReactNodeArray) => ( + + {chunks} + + ), + }, + )} + +
    + ); + }; + const handleOnBlur = (e: FocusEvent, inputId: string) => { const text = e.target.value; if (!text) { @@ -736,6 +809,7 @@ const Signup = ({onCustomizeHeader}: SignupProps) => { error={passwordError} onBlur={(e) => handleOnBlur(e, 'password')} /> + {getNewsletterCheck()} void; + checked: boolean; +} + +function CheckInput(props: Props) { + return ( +
    + + {props.text} +
    + ); +} + +export default CheckInput; diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index e273515c5a..c1f0bacbc9 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -4254,6 +4254,9 @@ "navbar.viewPinnedPosts": "View Pinned Posts", "newChannelWithBoard.tutorialTip.description": "The board you just created can be quickly accessed by clicking on the Boards icon in the App bar. You can view the boards that are linked to this channel in the right-hand sidebar and open one in full view.", "newChannelWithBoard.tutorialTip.title": "Access linked boards from the App Bar", + "newsletter_optin.checkmark.text": "I would like to receive Mattermost security updates via newsletter. Data Terms and Conditions apply", + "newsletter_optin.desc": "Sign up at {link}.", + "newsletter_optin.title": "Interested in receiving Mattermost security updates via newsletter?", "next_steps_view.welcomeToMattermost": "Welcome to Mattermost", "no_results.channel_files_filtered.subtitle": "This channel doesn't contains any file with the selected file format.", "no_results.channel_files_filtered.title": "No files found", diff --git a/webapp/channels/src/utils/constants.tsx b/webapp/channels/src/utils/constants.tsx index 7ea14fc0fa..d7e4644af2 100644 --- a/webapp/channels/src/utils/constants.tsx +++ b/webapp/channels/src/utils/constants.tsx @@ -1077,6 +1077,7 @@ export const HostedCustomerLinks = { BILLING_DOCS: 'https://mattermost.com/pl/how-self-hosted-billing-works', SELF_HOSTED_BILLING: 'https://docs.mattermost.com/manage/self-hosted-billing.html', TERMS_AND_CONDITIONS: 'https://mattermost.com/enterprise-edition-terms/', + SECURITY_UPDATES: 'https://mattermost.com/security-updates/', }; export const DocLinks = { diff --git a/webapp/platform/client/src/client4.ts b/webapp/platform/client/src/client4.ts index 063c706732..a58b1655ba 100644 --- a/webapp/platform/client/src/client4.ts +++ b/webapp/platform/client/src/client4.ts @@ -26,6 +26,7 @@ import { CreateSubscriptionRequest, Feedback, WorkspaceDeletionRequest, + NewsletterRequestBody, } from '@mattermost/types/cloud'; import { SelfHostedSignupForm, @@ -3893,6 +3894,13 @@ export default class Client4 { ); }; + subscribeToNewsletter = (newletterRequestBody: NewsletterRequestBody) => { + return this.doFetch( + `${this.getHostedCustomerRoute()}/subscribe-newsletter`, + {method: 'post', body: JSON.stringify(newletterRequestBody)}, + ); + }; + createPaymentMethod = async () => { return this.doFetch( `${this.getCloudRoute()}/payment`, diff --git a/webapp/platform/types/src/cloud.ts b/webapp/platform/types/src/cloud.ts index 36a586f7be..74b7195ab2 100644 --- a/webapp/platform/types/src/cloud.ts +++ b/webapp/platform/types/src/cloud.ts @@ -220,6 +220,11 @@ export interface CreateSubscriptionRequest { internal_purchase_order?: string; } +export interface NewsletterRequestBody { + email: string; + subscribed_content: string; +} + export const areShippingDetailsValid = (address: Address | null | undefined): boolean => { if (!address) { return false; From f218c105ec9f8e59b532e255d860b1fae78c5132 Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Tue, 4 Apr 2023 11:26:12 -0400 Subject: [PATCH 40/58] replace external link with a button. --- .../billing/delete_workspace/delete_workspace_cta.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx b/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx index ef8ec25dad..22821eaf60 100644 --- a/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx +++ b/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx @@ -80,17 +80,15 @@ export default function DeleteWorkspaceCTA() { }} />
  • - - +
    ); From 2c69315bc8095734e024315ecd9a1431a74e17d2 Mon Sep 17 00:00:00 2001 From: Conor Macpherson Date: Tue, 4 Apr 2023 11:45:02 -0400 Subject: [PATCH 41/58] lint. --- .../billing/delete_workspace/delete_workspace_cta.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx b/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx index 22821eaf60..ccdf364756 100644 --- a/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx +++ b/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx @@ -15,8 +15,6 @@ import {isCloudLicense} from 'utils/license_utils'; import {getCloudSubscription, getSubscriptionProduct} from 'mattermost-redux/selectors/entities/cloud'; -import ExternalLink from 'components/external_link'; - import DeleteWorkspaceModal from './delete_workspace_modal'; export default function DeleteWorkspaceCTA() { From 6919761122d2409e805d0279169a7925c6e5687d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Tue, 4 Apr 2023 18:04:06 +0200 Subject: [PATCH 42/58] MM-49862 - remove no longer needed webapp calls to action and pulsating dots (#22699) * MM-49862 - remove no longer needed webapp calls to action and pulsating dots * fix snapshots * improve function logic based on pr comments * fix unit tests --------- Co-authored-by: Mattermost Build --- .../__snapshots__/actions_menu.test.tsx.snap | 3 - .../actions_menu/actions_menu.test.tsx | 5 - .../components/actions_menu/actions_menu.tsx | 23 -- .../actions_menu/actions_menu_empty.test.tsx | 5 - .../actions_menu/actions_menu_mobile.test.tsx | 5 - .../__snapshots__/dot_menu.test.tsx.snap | 214 ------------------ .../src/components/dot_menu/dot_menu.test.tsx | 27 --- .../src/components/dot_menu/dot_menu.tsx | 31 +-- .../dot_menu/dot_menu_empty.test.tsx | 1 - .../dot_menu/dot_menu_mobile.test.tsx | 1 - .../channels/src/components/dot_menu/index.ts | 4 - webapp/channels/src/components/post/index.tsx | 8 +- .../src/components/post/post_component.tsx | 2 - .../src/components/post/post_options.tsx | 37 +-- .../thread_viewer_row.tsx | 1 - .../virtualized_thread_viewer.tsx | 1 - .../src/selectors/views/custom_status.test.ts | 29 +++ .../src/selectors/views/custom_status.ts | 7 +- webapp/channels/src/utils/utils.tsx | 51 ++++- 19 files changed, 94 insertions(+), 361 deletions(-) diff --git a/webapp/channels/src/components/actions_menu/__snapshots__/actions_menu.test.tsx.snap b/webapp/channels/src/components/actions_menu/__snapshots__/actions_menu.test.tsx.snap index 60367b08bf..26709a01ad 100644 --- a/webapp/channels/src/components/actions_menu/__snapshots__/actions_menu.test.tsx.snap +++ b/webapp/channels/src/components/actions_menu/__snapshots__/actions_menu.test.tsx.snap @@ -39,7 +39,6 @@ exports[`components/actions_menu/ActionsMenu has actions - marketplace disabled className="post-menu__item post-menu__item--active" id="center_actions_button_post_id_1" key="more-actions-button" - onClick={[Function]} type="button" > { isSysAdmin: true, pluginMenuItems: [], post: TestHelper.getPostMock({id: 'post_id_1', is_pinned: false, type: '' as PostType}), - showTutorialTip: false, components: {}, - handleOpenTip: jest.fn(), - handleNextTip: jest.fn(), - handleDismissTip: jest.fn(), - showPulsatingDot: false, location: 'center', canOpenMarketplace: false, actions: { diff --git a/webapp/channels/src/components/actions_menu/actions_menu.tsx b/webapp/channels/src/components/actions_menu/actions_menu.tsx index e20023c77b..d141f1f121 100644 --- a/webapp/channels/src/components/actions_menu/actions_menu.tsx +++ b/webapp/channels/src/components/actions_menu/actions_menu.tsx @@ -17,7 +17,6 @@ import {AppCallResponseTypes} from 'mattermost-redux/constants/apps'; import {HandleBindingClick, PostEphemeralCallResponseForPost, OpenAppsModal} from 'types/apps'; import {Locations, Constants, ModalIdentifiers} from 'utils/constants'; import Permissions from 'mattermost-redux/constants/permissions'; -import {ActionsTutorialTip} from 'components/actions_menu/actions_menu_tutorial_tip'; import {ModalData} from 'types/actions'; import MarketplaceModal, {OpenedFromType} from 'components/plugin_marketplace/marketplace_modal'; import OverlayTrigger from 'components/overlay_trigger'; @@ -44,11 +43,6 @@ export type Props = { pluginMenuItems?: PluginComponent[]; post: Post; teamId: string; - handleOpenTip: () => void; - handleNextTip: (e: React.MouseEvent) => void; - handleDismissTip: () => void; - showPulsatingDot?: boolean; - showTutorialTip: boolean; canOpenMarketplace: boolean; /** @@ -236,14 +230,6 @@ export class ActionMenuClass extends React.PureComponent { ); } - handleActionsIconClick = (e: React.MouseEvent) => { - if (this.props.showPulsatingDot || this.props.showTutorialTip) { - this.props.handleOpenTip(); - e.preventDefault(); - e.stopPropagation(); - } - }; - renderDivider = (suffix: string): React.ReactNode => { return (
  • { })} type='button' aria-expanded='false' - onClick={this.handleActionsIconClick} > - {this.props.showPulsatingDot && - - } { }, appBindings: [], pluginMenuItems: [], - handleOpenTip: jest.fn(), - handleNextTip: jest.fn(), - handleDismissTip: jest.fn(), - showPulsatingDot: false, - showTutorialTip: false, appsEnabled: false, isSysAdmin: true, canOpenMarketplace: false, diff --git a/webapp/channels/src/components/actions_menu/actions_menu_mobile.test.tsx b/webapp/channels/src/components/actions_menu/actions_menu_mobile.test.tsx index 3f4f3c3534..cdd71a8390 100644 --- a/webapp/channels/src/components/actions_menu/actions_menu_mobile.test.tsx +++ b/webapp/channels/src/components/actions_menu/actions_menu_mobile.test.tsx @@ -37,11 +37,6 @@ describe('components/actions_menu/ActionsMenu on mobile view', () => { }, appBindings: [], pluginMenuItems: [], - handleOpenTip: jest.fn(), - handleNextTip: jest.fn(), - handleDismissTip: jest.fn(), - showPulsatingDot: false, - showTutorialTip: false, appsEnabled: false, isSysAdmin: true, canOpenMarketplace: false, diff --git a/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap b/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap index 9970088867..490e16e2da 100644 --- a/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap +++ b/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap @@ -107,113 +107,6 @@ Object { } `; -exports[`components/dot_menu/DotMenu should match snapshot, hide "New" badge on forward post 1`] = ` -Object { - "asFragment": [Function], - "baseElement": -
    - -
    - , - "container":
    - -
    , - "debug": [Function], - "findAllByAltText": [Function], - "findAllByDisplayValue": [Function], - "findAllByLabelText": [Function], - "findAllByPlaceholderText": [Function], - "findAllByRole": [Function], - "findAllByTestId": [Function], - "findAllByText": [Function], - "findAllByTitle": [Function], - "findByAltText": [Function], - "findByDisplayValue": [Function], - "findByLabelText": [Function], - "findByPlaceholderText": [Function], - "findByRole": [Function], - "findByTestId": [Function], - "findByText": [Function], - "findByTitle": [Function], - "getAllByAltText": [Function], - "getAllByDisplayValue": [Function], - "getAllByLabelText": [Function], - "getAllByPlaceholderText": [Function], - "getAllByRole": [Function], - "getAllByTestId": [Function], - "getAllByText": [Function], - "getAllByTitle": [Function], - "getByAltText": [Function], - "getByDisplayValue": [Function], - "getByLabelText": [Function], - "getByPlaceholderText": [Function], - "getByRole": [Function], - "getByTestId": [Function], - "getByText": [Function], - "getByTitle": [Function], - "queryAllByAltText": [Function], - "queryAllByDisplayValue": [Function], - "queryAllByLabelText": [Function], - "queryAllByPlaceholderText": [Function], - "queryAllByRole": [Function], - "queryAllByTestId": [Function], - "queryAllByText": [Function], - "queryAllByTitle": [Function], - "queryByAltText": [Function], - "queryByDisplayValue": [Function], - "queryByLabelText": [Function], - "queryByPlaceholderText": [Function], - "queryByRole": [Function], - "queryByTestId": [Function], - "queryByText": [Function], - "queryByTitle": [Function], - "rerender": [Function], - "unmount": [Function], -} -`; - exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = ` `; - -exports[`components/dot_menu/DotMenu should match snapshot, show "New" badge on forward post 1`] = ` -Object { - "asFragment": [Function], - "baseElement": -
    - -
    - , - "container":
    - -
    , - "debug": [Function], - "findAllByAltText": [Function], - "findAllByDisplayValue": [Function], - "findAllByLabelText": [Function], - "findAllByPlaceholderText": [Function], - "findAllByRole": [Function], - "findAllByTestId": [Function], - "findAllByText": [Function], - "findAllByTitle": [Function], - "findByAltText": [Function], - "findByDisplayValue": [Function], - "findByLabelText": [Function], - "findByPlaceholderText": [Function], - "findByRole": [Function], - "findByTestId": [Function], - "findByText": [Function], - "findByTitle": [Function], - "getAllByAltText": [Function], - "getAllByDisplayValue": [Function], - "getAllByLabelText": [Function], - "getAllByPlaceholderText": [Function], - "getAllByRole": [Function], - "getAllByTestId": [Function], - "getAllByText": [Function], - "getAllByTitle": [Function], - "getByAltText": [Function], - "getByDisplayValue": [Function], - "getByLabelText": [Function], - "getByPlaceholderText": [Function], - "getByRole": [Function], - "getByTestId": [Function], - "getByText": [Function], - "getByTitle": [Function], - "queryAllByAltText": [Function], - "queryAllByDisplayValue": [Function], - "queryAllByLabelText": [Function], - "queryAllByPlaceholderText": [Function], - "queryAllByRole": [Function], - "queryAllByTestId": [Function], - "queryAllByText": [Function], - "queryAllByTitle": [Function], - "queryByAltText": [Function], - "queryByDisplayValue": [Function], - "queryByLabelText": [Function], - "queryByPlaceholderText": [Function], - "queryByRole": [Function], - "queryByTestId": [Function], - "queryByText": [Function], - "queryByTitle": [Function], - "rerender": [Function], - "unmount": [Function], -} -`; diff --git a/webapp/channels/src/components/dot_menu/dot_menu.test.tsx b/webapp/channels/src/components/dot_menu/dot_menu.test.tsx index e807940ead..402cf954b1 100644 --- a/webapp/channels/src/components/dot_menu/dot_menu.test.tsx +++ b/webapp/channels/src/components/dot_menu/dot_menu.test.tsx @@ -146,7 +146,6 @@ describe('components/dot_menu/DotMenu', () => { threadReplyCount: 0, userId: 'user_id_1', isMilitaryTime: false, - showForwardPostNewLabel: false, }; test('should match snapshot, on Center', () => { @@ -181,32 +180,6 @@ describe('components/dot_menu/DotMenu', () => { expect(wrapper).toMatchSnapshot(); }); - test('should match snapshot, show "New" badge on forward post', () => { - const props = { - ...baseProps, - showForwardPostNewLabel: true, - }; - const wrapper = renderWithIntlAndStore( - , - initialState, - ); - - expect(wrapper).toMatchSnapshot(); - }); - - test('should match snapshot, hide "New" badge on forward post', () => { - const props = { - ...baseProps, - showForwardPostNewLabel: false, - }; - const wrapper = renderWithIntlAndStore( - , - initialState, - ); - - expect(wrapper).toMatchSnapshot(); - }); - test('should show mark as unread when channel is not archived', () => { const props = { ...baseProps, diff --git a/webapp/channels/src/components/dot_menu/dot_menu.tsx b/webapp/channels/src/components/dot_menu/dot_menu.tsx index 135fb04593..df164cf18f 100644 --- a/webapp/channels/src/components/dot_menu/dot_menu.tsx +++ b/webapp/channels/src/components/dot_menu/dot_menu.tsx @@ -25,7 +25,7 @@ import { import Permissions from 'mattermost-redux/constants/permissions'; -import {Locations, ModalIdentifiers, Constants, TELEMETRY_LABELS, Preferences} from 'utils/constants'; +import {Locations, ModalIdentifiers, Constants, TELEMETRY_LABELS} from 'utils/constants'; import DeletePostModal from 'components/delete_post_modal'; import DelayedAction from 'utils/delayed_action'; import * as PostUtils from 'utils/post_utils'; @@ -33,12 +33,10 @@ import * as Menu from 'components/menu'; import * as Utils from 'utils/utils'; import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate'; import {ModalData} from 'types/actions'; -import {PluginComponent} from 'types/store/plugins'; import {UserThread} from '@mattermost/types/threads'; import {Post} from '@mattermost/types/posts'; import ForwardPostModal from '../forward_post_modal'; -import Tag from '../widgets/tag/tag'; import {ChangeEvent, trackDotMenuEvent} from './utils'; @@ -70,20 +68,11 @@ type Props = { postEditTimeLimit?: string; // TechDebt: Made non-mandatory while converting to typescript enableEmojiPicker?: boolean; // TechDebt: Made non-mandatory while converting to typescript channelIsArchived?: boolean; // TechDebt: Made non-mandatory while converting to typescript - currentTeamUrl?: string; // TechDebt: Made non-mandatory while converting to typescript teamUrl?: string; // TechDebt: Made non-mandatory while converting to typescript isMobileView: boolean; - showForwardPostNewLabel: boolean; timezone?: string; isMilitaryTime: boolean; - /** - * Components for overriding provided by plugins - */ - components: { - [componentName: string]: PluginComponent[]; - }; - actions: { /** @@ -292,9 +281,6 @@ export class DotMenuClass extends React.PureComponent { }, }; - if (this.props.showForwardPostNewLabel) { - this.props.actions.setGlobalItem(Preferences.FORWARD_POST_VIEWED, false); - } this.props.actions.openModal(forwardPostModalData); } @@ -441,15 +427,6 @@ export class DotMenuClass extends React.PureComponent { id='forward_post_button.label' defaultMessage='Forward' /> - {this.props.showForwardPostNewLabel && ( - - )} ); @@ -519,12 +496,12 @@ export class DotMenuClass extends React.PureComponent { class: classNames('post-menu__item', { 'post-menu__item--active': this.props.isMenuOpen, }), - 'aria-label': this.props.intl.formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'Actions'}), + 'aria-label': formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'Actions'}), children: , }} menu={{ id: `${this.props.location}_dropdown_${this.props.post.id}`, - 'aria-label': this.props.intl.formatMessage({id: 'post_info.menuAriaLabel', defaultMessage: 'Post extra options'}), + 'aria-label': formatMessage({id: 'post_info.menuAriaLabel', defaultMessage: 'Post extra options'}), onKeyDown: this.onShortcutKeyDown, width: '264px', onToggle: this.handleMenuToggle, @@ -532,7 +509,7 @@ export class DotMenuClass extends React.PureComponent { }} menuButtonTooltip={{ id: `PostDotMenu-ButtonTooltip-${this.props.post.id}`, - text: this.props.intl.formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'More'}), + text: formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'More'}), class: 'hidden-xs', }} > diff --git a/webapp/channels/src/components/dot_menu/dot_menu_empty.test.tsx b/webapp/channels/src/components/dot_menu/dot_menu_empty.test.tsx index dd9b38594b..c5b2e454d1 100644 --- a/webapp/channels/src/components/dot_menu/dot_menu_empty.test.tsx +++ b/webapp/channels/src/components/dot_menu/dot_menu_empty.test.tsx @@ -59,7 +59,6 @@ describe('components/dot_menu/DotMenu returning empty ("")', () => { threadId: 'post_id_1', userId: 'user_id_1', isMilitaryTime: false, - showForwardPostNewLabel: false, }; const wrapper = shallow( diff --git a/webapp/channels/src/components/dot_menu/dot_menu_mobile.test.tsx b/webapp/channels/src/components/dot_menu/dot_menu_mobile.test.tsx index a6ecb1761c..cd3f1d23a8 100644 --- a/webapp/channels/src/components/dot_menu/dot_menu_mobile.test.tsx +++ b/webapp/channels/src/components/dot_menu/dot_menu_mobile.test.tsx @@ -59,7 +59,6 @@ describe('components/dot_menu/DotMenu on mobile view', () => { threadId: 'post_id_1', userId: 'user_id_1', isMilitaryTime: false, - showForwardPostNewLabel: false, }; const wrapper = shallow( diff --git a/webapp/channels/src/components/dot_menu/index.ts b/webapp/channels/src/components/dot_menu/index.ts index fa1623fa2c..e9d765ba59 100644 --- a/webapp/channels/src/components/dot_menu/index.ts +++ b/webapp/channels/src/components/dot_menu/index.ts @@ -44,7 +44,6 @@ import {matchUserMentionTriggersWithMessageMentions} from 'utils/post_utils'; import {Post} from '@mattermost/types/posts'; import {setGlobalItem} from '../../actions/storage'; -import {getGlobalItem} from '../../selectors/storage'; import DotMenu from './dot_menu'; @@ -110,8 +109,6 @@ function makeMapStateToProps() { } } - const showForwardPostNewLabel = getGlobalItem(state, Preferences.FORWARD_POST_VIEWED, true); - return { channelIsArchived: isArchivedChannel(channel), components: state.plugins.components, @@ -129,7 +126,6 @@ function makeMapStateToProps() { isCollapsedThreadsEnabled: collapsedThreads, threadReplyCount, isMobileView: getIsMobileView(state), - showForwardPostNewLabel, timezone: getCurrentUserTimezone(state), isMilitaryTime, }; diff --git a/webapp/channels/src/components/post/index.tsx b/webapp/channels/src/components/post/index.tsx index 2bd3324d9f..39c664736f 100644 --- a/webapp/channels/src/components/post/index.tsx +++ b/webapp/channels/src/components/post/index.tsx @@ -4,7 +4,6 @@ import {connect, ConnectedProps} from 'react-redux'; import {AnyAction, bindActionCreators, Dispatch} from 'redux'; -import {showActionsDropdownPulsatingDot} from 'selectors/actions_menu'; import {setActionsMenuInitialisationState} from 'mattermost-redux/actions/preferences'; import {getConfig} from 'mattermost-redux/selectors/entities/general'; import {getPost, makeGetCommentCountForPost, makeIsPostCommentMention, isPostAcknowledgementsEnabled, isPostPriorityEnabled, UserActivityPost} from 'mattermost-redux/selectors/entities/posts'; @@ -13,7 +12,6 @@ import { get, getBool, isCollapsedThreadsEnabled, - onboardingTourTipsEnabled, } from 'mattermost-redux/selectors/entities/preferences'; import {getCurrentTeam, getCurrentTeamId, getTeam, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams'; import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users'; @@ -129,8 +127,7 @@ function makeMapStateToProps() { const user = getUser(state, post.user_id); const isBot = Boolean(user && user.is_bot); const highlightedPostId = getHighlightedPostId(state); - const showActionsMenuPulsatingDot = showActionsDropdownPulsatingDot(state); - const tourTipsEnabled = onboardingTourTipsEnabled(state); + const selectedCard = getSelectedPostCard(state); let emojis: Emoji[] = []; @@ -203,8 +200,7 @@ function makeMapStateToProps() { compactDisplay: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT, colorizeUsernames: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLORIZE_USERNAMES, Preferences.COLORIZE_USERNAMES_DEFAULT) === 'true', shouldShowActionsMenu: shouldShowActionsMenu(state, post), - showActionsMenuPulsatingDot, - tourTipsEnabled, + shortcutReactToLastPostEmittedFrom, isBot, collapsedThreadsEnabled: isCollapsedThreadsEnabled(state), diff --git a/webapp/channels/src/components/post/post_component.tsx b/webapp/channels/src/components/post/post_component.tsx index 2559cc56e1..907792dcd1 100644 --- a/webapp/channels/src/components/post/post_component.tsx +++ b/webapp/channels/src/components/post/post_component.tsx @@ -114,8 +114,6 @@ export type Props = { isPostAcknowledgementsEnabled: boolean; isPostPriorityEnabled: boolean; isCardOpen?: boolean; - shouldShowDotMenu: boolean; - tourTipsEnabled: boolean; }; const PostComponent = (props: Props): JSX.Element => { diff --git a/webapp/channels/src/components/post/post_options.tsx b/webapp/channels/src/components/post/post_options.tsx index b5e12801b8..d163c8c4bd 100644 --- a/webapp/channels/src/components/post/post_options.tsx +++ b/webapp/channels/src/components/post/post_options.tsx @@ -5,7 +5,7 @@ import React, {ReactNode, useEffect, useRef, useState} from 'react'; import {FormattedMessage} from 'react-intl'; -import {Posts, Preferences} from 'mattermost-redux/constants/index'; +import {Posts} from 'mattermost-redux/constants/index'; import {isPostEphemeral} from 'mattermost-redux/utils/post_utils'; import {Locations} from 'utils/constants'; @@ -34,8 +34,6 @@ type Props = { handleDropdownOpened?: (e: boolean) => void; collapsedThreadsEnabled?: boolean; shouldShowActionsMenu?: boolean; - showActionsMenuPulsatingDot?: boolean; - tourTipsEnabled: boolean; oneClickReactionsEnabled?: boolean; recentEmojis: Emoji[]; isExpanded?: boolean; @@ -51,7 +49,6 @@ type Props = { shortcutReactToLastPostEmittedFrom?: string; isPostHeaderVisible?: boolean | null; isPostBeingEdited?: boolean; - shouldShowDotMenu: boolean; actions: { emitShortcutReactToLastPostFrom: (emittedFrom: 'CENTER' | 'RHS_ROOT' | 'NO_WHERE') => void; }; @@ -63,7 +60,6 @@ const PostOptions = (props: Props): JSX.Element => { const [showEmojiPicker, setShowEmojiPicker] = useState(false); const [showDotMenu, setShowDotMenu] = useState(false); const [showActionsMenu, setShowActionsMenu] = useState(false); - const [showActionTip, setShowActionTip] = useState(false); useEffect(() => { if (props.isLastPost && @@ -80,8 +76,6 @@ const PostOptions = (props: Props): JSX.Element => { isReadOnly, post, oneClickReactionsEnabled, - showActionsMenuPulsatingDot, - tourTipsEnabled, isMobileView, } = props; @@ -102,34 +96,14 @@ const PostOptions = (props: Props): JSX.Element => { }; const handleActionsMenuOpened = (open: boolean) => { - if (tourTipsEnabled && showActionsMenuPulsatingDot) { - setShowActionTip(true); - return; - } setShowActionsMenu(open); props.handleDropdownOpened!(open); }; - const handleActionsMenuTipOpened = () => { - setShowActionTip(true); - props.handleDropdownOpened!(true); - }; - - const handleActionsMenuGotItClick = () => { - props.setActionsMenuInitialisationState?.(({[Preferences.ACTIONS_MENU_VIEWED]: true})); - setShowActionTip(false); - props.handleDropdownOpened!(false); - }; - - const handleTipDismissed = () => { - setShowActionTip(false); - props.handleDropdownOpened!(false); - }; - const getDotMenuRef = () => dotMenuRef.current; const isPostDeleted = post && post.state === Posts.POST_DELETED; - const hoverLocal = props.hover || showEmojiPicker || showDotMenu || showActionsMenu || showActionTip; + const hoverLocal = props.hover || showEmojiPicker || showDotMenu || showActionsMenu; const showCommentIcon = isFromAutoResponder || (!systemMessage && (isMobileView || hoverLocal || (!post.root_id && Boolean(props.hasReplies)) || props.isFirstReply) && props.location === Locations.CENTER); @@ -197,11 +171,6 @@ const PostOptions = (props: Props): JSX.Element => { location={props.location} handleDropdownOpened={handleActionsMenuOpened} isMenuOpen={showActionsMenu} - showPulsatingDot={tourTipsEnabled && showActionsMenuPulsatingDot} - showTutorialTip={tourTipsEnabled && showActionTip} - handleOpenTip={handleActionsMenuTipOpened} - handleNextTip={handleActionsMenuGotItClick} - handleDismissTip={handleTipDismissed} /> ); const dotMenu = ( @@ -231,7 +200,7 @@ const PostOptions = (props: Props): JSX.Element => {
  • ); - } else if (isPostDeleted || !props.shouldShowDotMenu) { + } else if (isPostDeleted) { options = null; } else if (props.location === Locations.SEARCH) { const hasCRTFooter = props.collapsedThreadsEnabled && !post.root_id && (post.reply_count > 0 || post.is_following); diff --git a/webapp/channels/src/components/threading/virtualized_thread_viewer/thread_viewer_row.tsx b/webapp/channels/src/components/threading/virtualized_thread_viewer/thread_viewer_row.tsx index b26051f723..4917f2fa79 100644 --- a/webapp/channels/src/components/threading/virtualized_thread_viewer/thread_viewer_row.tsx +++ b/webapp/channels/src/components/threading/virtualized_thread_viewer/thread_viewer_row.tsx @@ -27,7 +27,6 @@ type Props = { previousPostId: string; teamId: string; timestampProps?: Partial; - lastPost: Post; }; function noop() {} diff --git a/webapp/channels/src/components/threading/virtualized_thread_viewer/virtualized_thread_viewer.tsx b/webapp/channels/src/components/threading/virtualized_thread_viewer/virtualized_thread_viewer.tsx index 09fc561d00..4cafae3823 100644 --- a/webapp/channels/src/components/threading/virtualized_thread_viewer/virtualized_thread_viewer.tsx +++ b/webapp/channels/src/components/threading/virtualized_thread_viewer/virtualized_thread_viewer.tsx @@ -403,7 +403,6 @@ class ThreadViewerVirtualized extends PureComponent { previousPostId={getPreviousPostId(data, index)} teamId={this.props.teamId} timestampProps={this.props.useRelativeTimestamp ? THREADING_TIME : undefined} - lastPost={this.props.lastPost} /> ); diff --git a/webapp/channels/src/selectors/views/custom_status.test.ts b/webapp/channels/src/selectors/views/custom_status.test.ts index fdbf13af94..8642fbc0ed 100644 --- a/webapp/channels/src/selectors/views/custom_status.test.ts +++ b/webapp/channels/src/selectors/views/custom_status.test.ts @@ -11,6 +11,7 @@ import {makeGetCustomStatus, getRecentCustomStatuses, isCustomStatusEnabled, sho import {TestHelper} from 'utils/test_helper'; import {CustomStatusDuration} from '@mattermost/types/users'; +import {addTimeToTimestamp, TimeInformation} from 'utils/utils'; jest.mock('mattermost-redux/selectors/entities/users'); jest.mock('mattermost-redux/selectors/entities/general'); @@ -86,6 +87,7 @@ describe('isCustomStatusEnabled', () => { }); describe('showStatusDropdownPulsatingDot and showPostHeaderUpdateStatusButton', () => { + const user = TestHelper.getUserMock(); const preference = { myPreference: { value: '', @@ -104,4 +106,31 @@ describe('showStatusDropdownPulsatingDot and showPostHeaderUpdateStatusButton', (PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value); expect(showPostHeaderUpdateStatusButton(store.getState())).toBeFalsy(); }); + + it('should return false if user was created less than seven days before from today', async () => { + const store = await configureStore(); + (PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value); + const todayTimestamp = new Date().getTime(); + + // set the user create date to 6 days in the past from today + const todayMinusSixDays = addTimeToTimestamp(todayTimestamp, TimeInformation.DAYS, 6, TimeInformation.PAST); + const newUser = {...user, create_at: todayMinusSixDays}; + newUser.props.customStatus = JSON.stringify(customStatus); + (UserSelectors.getCurrentUser as jest.Mock).mockReturnValue(newUser); + expect(showStatusDropdownPulsatingDot(store.getState())).toBeFalsy(); + }); + + it('should return true if user was created more than seven days before from today', async () => { + const store = await configureStore(); + preference.myPreference.value = JSON.stringify({[Preferences.CUSTOM_STATUS_MODAL_VIEWED]: false}); + (PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value); + const todayTimestamp = new Date().getTime(); + + // set the user create date to 8 days in the past from today + const todayMinusEightDays = addTimeToTimestamp(todayTimestamp, TimeInformation.DAYS, 8, TimeInformation.PAST); + const newUser = {...user, create_at: todayMinusEightDays}; + newUser.props.customStatus = JSON.stringify(customStatus); + (UserSelectors.getCurrentUser as jest.Mock).mockReturnValue(newUser); + expect(showStatusDropdownPulsatingDot(store.getState())).toBeTruthy(); + }); }); diff --git a/webapp/channels/src/selectors/views/custom_status.ts b/webapp/channels/src/selectors/views/custom_status.ts index 80b2a93215..6d7742ccb4 100644 --- a/webapp/channels/src/selectors/views/custom_status.ts +++ b/webapp/channels/src/selectors/views/custom_status.ts @@ -12,6 +12,8 @@ import {get} from 'mattermost-redux/selectors/entities/preferences'; import {Preferences} from 'mattermost-redux/constants'; import {CustomStatusDuration, UserCustomStatus} from '@mattermost/types/users'; +import {isDateWithinDaysRange, TimeInformation} from 'utils/utils'; + import {GlobalState} from 'types/store'; import {getCurrentUserTimezone} from 'selectors/general'; import {getCurrentMomentForTimezone} from 'utils/timezone'; @@ -56,9 +58,12 @@ export function isCustomStatusEnabled(state: GlobalState) { } function showCustomStatusPulsatingDotAndPostHeader(state: GlobalState) { + // only show this for users after the first seven days + const currentUser = getCurrentUser(state); + const hasUserCreationMoreThanSevenDays = isDateWithinDaysRange(currentUser?.create_at, 7, TimeInformation.FUTURE); const customStatusTutorialState = get(state, Preferences.CATEGORY_CUSTOM_STATUS, Preferences.NAME_CUSTOM_STATUS_TUTORIAL_STATE); const modalAlreadyViewed = customStatusTutorialState && JSON.parse(customStatusTutorialState)[Preferences.CUSTOM_STATUS_MODAL_VIEWED]; - return !modalAlreadyViewed; + return !modalAlreadyViewed && hasUserCreationMoreThanSevenDays; } export function showStatusDropdownPulsatingDot(state: GlobalState) { diff --git a/webapp/channels/src/utils/utils.tsx b/webapp/channels/src/utils/utils.tsx index 4cdc34e57c..9f71b304d5 100644 --- a/webapp/channels/src/utils/utils.tsx +++ b/webapp/channels/src/utils/utils.tsx @@ -90,6 +90,23 @@ const CLICKABLE_ELEMENTS = [ 'audio', 'video', ]; +const MS_PER_SECOND = 1000; +const MS_PER_MINUTE = 60 * MS_PER_SECOND; +const MS_PER_HOUR = 60 * MS_PER_MINUTE; +const MS_PER_DAY = 24 * MS_PER_HOUR; + +export enum TimeInformation { + MILLISECONDS = 'm', + SECONDS = 's', + MINUTES = 'x', + HOURS = 'h', + DAYS = 'd', + FUTURE = 'f', + PAST = 'p' +} + +export type TimeUnit = Exclude; +export type TimeDirection = TimeInformation.FUTURE | TimeInformation.PAST; export function isMac() { return navigator.platform.toUpperCase().indexOf('MAC') >= 0; @@ -256,7 +273,6 @@ export function getTimestamp(): number { } export function getRemainingDaysFromFutureTimestamp(timestamp?: number): number { - const MS_PER_DAY = 24 * 60 * 60 * 1000; const futureDate = new Date(timestamp as number); const utcFuture = Date.UTC(futureDate.getFullYear(), futureDate.getMonth(), futureDate.getDate()); const today = new Date(); @@ -265,6 +281,39 @@ export function getRemainingDaysFromFutureTimestamp(timestamp?: number): number return Math.floor((utcFuture - utcToday) / MS_PER_DAY); } +export function addTimeToTimestamp(timestamp: number, type: TimeUnit, diff: number, timeline: TimeDirection) { + let modifier = 1; + switch (type) { + case TimeInformation.SECONDS: + modifier = MS_PER_SECOND; + break; + case TimeInformation.MINUTES: + modifier = MS_PER_MINUTE; + break; + case TimeInformation.HOURS: + modifier = MS_PER_HOUR; + break; + case TimeInformation.DAYS: + modifier = MS_PER_DAY; + break; + } + + return timeline === TimeInformation.FUTURE ? timestamp + (diff * modifier) : timestamp - (diff * modifier); +} + +/** + * Verifies if a date is in a particular given range of days from today + * @param timestamp date you want to check is in the range of the provided number of days from today + * @param days number of days you want to check your date against to + * @param timeline 'f' represents future, 'p' represents past + * @returns boolean, true if your date is in the range of the provided number of days + */ +export function isDateWithinDaysRange(timestamp: number, days: number, timeline: TimeDirection): boolean { + const today = new Date().getTime(); + const daysSince = Math.round((today - timestamp) / MS_PER_DAY); + return timeline === TimeInformation.PAST ? daysSince <= days : daysSince >= days; +} + export function getLocaleDateFromUTC(timestamp: number, format = 'YYYY/MM/DD HH:mm:ss', userTimezone = '') { if (!timestamp) { return moment.now(); From 42ae1536cb196124c1da6000e112634091a2e225 Mon Sep 17 00:00:00 2001 From: Dismated <77165959+Dismated@users.noreply.github.com> Date: Tue, 4 Apr 2023 19:28:40 +0300 Subject: [PATCH 43/58] MM-47095 Migrate AbstractIncomingWebhook to TypeScript (#22654) Co-authored-by: Mattermost Build --- .../channel_select/channel_select.tsx | 4 +- .../abstract_incoming_hook.test.tsx.snap | 56 +++---- .../abstract_incoming_hook.test.tsx | 31 +++- ...hook.jsx => abstract_incoming_webhook.tsx} | 155 ++++++++++-------- .../src/components/spinner_button.tsx | 5 +- 5 files changed, 148 insertions(+), 103 deletions(-) rename webapp/channels/src/components/integrations/{abstract_incoming_webhook.jsx => abstract_incoming_webhook.tsx} (79%) diff --git a/webapp/channels/src/components/channel_select/channel_select.tsx b/webapp/channels/src/components/channel_select/channel_select.tsx index d6b3a8e882..b7c32449d9 100644 --- a/webapp/channels/src/components/channel_select/channel_select.tsx +++ b/webapp/channels/src/components/channel_select/channel_select.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; +import React, {ChangeEventHandler} from 'react'; import {Channel} from '@mattermost/types/channels'; @@ -10,7 +10,7 @@ import * as Utils from 'utils/utils'; type Props = { channels: Channel[]; - onChange?: () => void; + onChange?: ChangeEventHandler; value?: string; selectOpen: boolean; selectPrivate: boolean; diff --git a/webapp/channels/src/components/integrations/__snapshots__/abstract_incoming_hook.test.tsx.snap b/webapp/channels/src/components/integrations/__snapshots__/abstract_incoming_hook.test.tsx.snap index 6bbb1f6e00..b8fb192a10 100644 --- a/webapp/channels/src/components/integrations/__snapshots__/abstract_incoming_hook.test.tsx.snap +++ b/webapp/channels/src/components/integrations/__snapshots__/abstract_incoming_hook.test.tsx.snap @@ -43,7 +43,7 @@ exports[`components/integrations/AbstractIncomingWebhook should call action func { - const team = {name: 'team_name'}; + const team: Team = {id: 'team_id', + create_at: 0, + update_at: 0, + delete_at: 0, + display_name: 'team_name', + name: 'team_name', + description: 'team_description', + email: 'team_email', + type: 'I', + company_name: 'team_company_name', + allowed_domains: 'team_allowed_domains', + invite_id: 'team_invite_id', + allow_open_invite: false, + scheme_id: 'team_scheme_id', + group_constrained: false, + }; const header = {id: 'header_id', defaultMessage: 'Header'}; const footer = {id: 'footer_id', defaultMessage: 'Footer'}; const loading = {id: 'loading_id', defaultMessage: 'Loading'}; @@ -16,6 +34,15 @@ describe('components/integrations/AbstractIncomingWebhook', () => { display_name: 'testIncomingWebhook', channel_id: '88cxd9wpzpbpfp8pad78xj75pr', description: 'testing', + id: 'test_id', + team_id: 'test_team_id', + create_at: 0, + update_at: 0, + delete_at: 0, + user_id: 'test_user_id', + username: '', + icon_url: '', + channel_locked: false, }; const enablePostUsernameOverride = true; const enablePostIconOverride = true; @@ -104,7 +131,7 @@ describe('components/integrations/AbstractIncomingWebhook', () => { }; const wrapper = shallow(); - wrapper.find('#channelId').simulate('change', evt); + wrapper.find(ChannelSelect).simulate('change', evt); expect(wrapper.state('channelId')).toBe(newChannelId); }); diff --git a/webapp/channels/src/components/integrations/abstract_incoming_webhook.jsx b/webapp/channels/src/components/integrations/abstract_incoming_webhook.tsx similarity index 79% rename from webapp/channels/src/components/integrations/abstract_incoming_webhook.jsx rename to webapp/channels/src/components/integrations/abstract_incoming_webhook.tsx index 498d811c99..af43262239 100644 --- a/webapp/channels/src/components/integrations/abstract_incoming_webhook.jsx +++ b/webapp/channels/src/components/integrations/abstract_incoming_webhook.tsx @@ -1,87 +1,100 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import PropTypes from 'prop-types'; -import React from 'react'; -import {FormattedMessage} from 'react-intl'; +import React, {ChangeEventHandler, FormEvent, MouseEvent, PureComponent} from 'react'; +import {FormattedMessage, MessageDescriptor} from 'react-intl'; import {Link} from 'react-router-dom'; import BackstageHeader from 'components/backstage/components/backstage_header'; import ChannelSelect from 'components/channel_select'; import FormError from 'components/form_error'; import SpinnerButton from 'components/spinner_button'; +import {Team} from '@mattermost/types/teams'; import {localizeMessage} from 'utils/utils'; +import {IncomingWebhook} from '@mattermost/types/integrations'; -export default class AbstractIncomingWebhook extends React.PureComponent { - static propTypes = { +interface State { + displayName: string; + description: string; + channelId: string; + channelLocked: boolean; + username: string; + iconURL: string; + saving: boolean; + serverError: string; + clientError: JSX.Element | null; +} - /** - * The current team - */ - team: PropTypes.object.isRequired, +interface Props { - /** - * The header text to render, has id and defaultMessage - */ - header: PropTypes.object.isRequired, + /** + * The current team + */ + team: Team; - /** - * The footer text to render, has id and defaultMessage - */ - footer: PropTypes.object.isRequired, + /** + * The header text to render, has id and defaultMessage + */ + header: MessageDescriptor; - /** - * The spinner loading text to render, has id and defaultMessage - */ - loading: PropTypes.object.isRequired, + /** + * The footer text to render, has id and defaultMessage + */ + footer: MessageDescriptor; - /** - * The server error text after a failed action - */ - serverError: PropTypes.string.isRequired, + /** + * The spinner loading text to render, has id and defaultMessage + */ + loading: MessageDescriptor; - /** - * The hook used to set the initial state - */ - initialHook: PropTypes.object, + /** + * The server error text after a failed action + */ + serverError: string; - /** - * Whether to allow configuration of the default post username. - */ - enablePostUsernameOverride: PropTypes.bool.isRequired, + /** + * The hook used to set the initial state + */ + initialHook?: IncomingWebhook | Record; - /** - * Whether to allow configuration of the default post icon. - */ - enablePostIconOverride: PropTypes.bool.isRequired, + /** + * Whether to allow configuration of the default post username. + */ + enablePostUsernameOverride: boolean; - /** - * The async function to run when the action button is pressed - */ - action: PropTypes.func.isRequired, - } + /** + * Whether to allow configuration of the default post icon. + */ + enablePostIconOverride: boolean; - constructor(props) { + /** + * The async function to run when the action button is pressed + */ + action: (hook: IncomingWebhook) => Promise; +} + +export default class AbstractIncomingWebhook extends PureComponent { + constructor(props: Props | Readonly) { super(props); this.state = this.getStateFromHook(this.props.initialHook || {}); } - getStateFromHook = (hook) => { + getStateFromHook = (hook: IncomingWebhook | Record) => { return { - displayName: hook.display_name || '', - description: hook.description || '', - channelId: hook.channel_id || '', - channelLocked: hook.channel_locked || false, - username: hook.username || '', - iconURL: hook.icon_url || '', + displayName: hook?.display_name || '', + description: hook?.description || '', + channelId: hook?.channel_id || '', + channelLocked: hook?.channel_locked || false, + username: hook?.username || '', + iconURL: hook?.icon_url || '', saving: false, serverError: '', clientError: null, }; } - handleSubmit = (e) => { + handleSubmit = (e: MouseEvent | FormEvent) => { e.preventDefault(); if (this.state.saving) { @@ -91,7 +104,7 @@ export default class AbstractIncomingWebhook extends React.PureComponent { this.setState({ saving: true, serverError: '', - clientError: '', + clientError: null, }); if (!this.state.channelId) { @@ -115,50 +128,56 @@ export default class AbstractIncomingWebhook extends React.PureComponent { description: this.state.description, username: this.state.username, icon_url: this.state.iconURL, + id: this.props.initialHook?.id || '', + create_at: this.props.initialHook?.create_at || 0, + update_at: this.props.initialHook?.update_at || 0, + delete_at: this.props.initialHook?.delete_at || 0, + team_id: this.props.initialHook?.team_id || '', + user_id: this.props.initialHook?.user_id || '', }; this.props.action(hook).then(() => this.setState({saving: false})); } - updateDisplayName = (e) => { + updateDisplayName: ChangeEventHandler = (e) => { this.setState({ displayName: e.target.value, }); } - updateDescription = (e) => { + updateDescription: ChangeEventHandler = (e) => { this.setState({ description: e.target.value, }); } - updateChannelId = (e) => { + updateChannelId: ChangeEventHandler = (e) => { this.setState({ channelId: e.target.value, }); } - updateChannelLocked = (e) => { + updateChannelLocked: ChangeEventHandler = (e) => { this.setState({ channelLocked: e.target.checked, }); } - updateUsername = (e) => { + updateUsername: ChangeEventHandler = (e) => { this.setState({ username: e.target.value, }); } - updateIconURL = (e) => { + updateIconURL: ChangeEventHandler = (e) => { this.setState({ iconURL: e.target.value, }); } render() { - var headerToRender = this.props.header; - var footerToRender = this.props.footer; + const headerToRender = this.props.header; + const footerToRender = this.props.footer; return (
    @@ -177,7 +196,7 @@ export default class AbstractIncomingWebhook extends React.PureComponent {
    this.handleSubmit(e)} >