From 48a6a641b777d395bbc1ed2e82007bafe5de4ceb Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:28:32 +0200 Subject: [PATCH] feat: Display license status (#787) * display license status * orange -> red * inform about the status on tabs --- web/src/i18n/en/index.ts | 14 ++++- web/src/i18n/i18n-types.ts | 56 +++++++++++++++++-- web/src/i18n/pl/index.ts | 16 ++++-- .../EnterpriseSettings/EnterpriseSettings.tsx | 6 +- .../LicenseSettings/LicenseSettings.tsx | 37 ++++++++++-- .../components/LicenseSettings/styles.scss | 16 ++++-- .../OpenIdSettings/OpenIdSettings.tsx | 6 +- 7 files changed, 122 insertions(+), 29 deletions(-) diff --git a/web/src/i18n/en/index.ts b/web/src/i18n/en/index.ts index 1f11278fc..6217edfb7 100644 --- a/web/src/i18n/en/index.ts +++ b/web/src/i18n/en/index.ts @@ -913,6 +913,7 @@ const en: BaseTranslation = { }, enterpriseOnly: { title: 'This feature is available only in Defguard Enterprise.', + currentExpired: 'Your current license has expired.', subtitle: 'To learn more, visit our ', website: 'website', }, @@ -1099,6 +1100,13 @@ const en: BaseTranslation = { }, }, fields: { + status: { + label: 'Status', + active: 'Active', + expired: 'Expired', + subscriptionHelper: + 'A subscription license is considered valid for some time after the expiration date to account for possible automatic payment delays.', + }, type: { label: 'Type', }, @@ -1574,11 +1582,11 @@ const en: BaseTranslation = { noConnection: `No connection established, please run provided command.`, connected: `Gateway connected.`, statusError: 'Failed to get gateway status', - oneLineInstall: `If you are doing one line install: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install + oneLineInstall: `If you are doing one line install: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install you don't need to do anything.`, - fromPackage: `Install the package available at https://github.com/DefGuard/gateway/releases/latest and configure \`/etc/defguard/gateway.toml\` + fromPackage: `Install the package available at https://github.com/DefGuard/gateway/releases/latest and configure \`/etc/defguard/gateway.toml\` according to the [documentation]({setupGatewayDocs:string}).`, - authToken: `Token below is required to authenticate and configure the gateway node. Ensure you keep this token secure and follow the deployment instructions + authToken: `Token below is required to authenticate and configure the gateway node. Ensure you keep this token secure and follow the deployment instructions provided in the [documentation]({setupGatewayDocs:string}) to successfully set up the gateway server. For more details and exact steps, please refer to the [documentation]({setupGatewayDocs:string}).`, dockerBasedGatewaySetup: `Below is a Docker based example. For more details and exact steps, please refer to the [documentation]({setupGatewayDocs:string}).`, diff --git a/web/src/i18n/i18n-types.ts b/web/src/i18n/i18n-types.ts index 7966d2d78..1046d6e97 100644 --- a/web/src/i18n/i18n-types.ts +++ b/web/src/i18n/i18n-types.ts @@ -2253,6 +2253,10 @@ type RootTranslation = { * T​h​i​s​ ​f​e​a​t​u​r​e​ ​i​s​ ​a​v​a​i​l​a​b​l​e​ ​o​n​l​y​ ​i​n​ ​D​e​f​g​u​a​r​d​ ​E​n​t​e​r​p​r​i​s​e​. */ title: string + /** + * Y​o​u​r​ ​c​u​r​r​e​n​t​ ​l​i​c​e​n​s​e​ ​h​a​s​ ​e​x​p​i​r​e​d​. + */ + currentExpired: string /** * T​o​ ​l​e​a​r​n​ ​m​o​r​e​,​ ​v​i​s​i​t​ ​o​u​r​ */ @@ -2664,6 +2668,24 @@ type RootTranslation = { } } fields: { + status: { + /** + * S​t​a​t​u​s + */ + label: string + /** + * A​c​t​i​v​e + */ + active: string + /** + * E​x​p​i​r​e​d + */ + expired: string + /** + * A​ ​s​u​b​s​c​r​i​p​t​i​o​n​ ​l​i​c​e​n​s​e​ ​i​s​ ​c​o​n​s​i​d​e​r​e​d​ ​v​a​l​i​d​ ​f​o​r​ ​s​o​m​e​ ​t​i​m​e​ ​a​f​t​e​r​ ​t​h​e​ ​e​x​p​i​r​a​t​i​o​n​ ​d​a​t​e​ ​t​o​ ​a​c​c​o​u​n​t​ ​f​o​r​ ​p​o​s​s​i​b​l​e​ ​a​u​t​o​m​a​t​i​c​ ​p​a​y​m​e​n​t​ ​d​e​l​a​y​s​. + */ + subscriptionHelper: string + } type: { /** * T​y​p​e @@ -3745,18 +3767,18 @@ type RootTranslation = { */ statusError: string /** - * I​f​ ​y​o​u​ ​a​r​e​ ​d​o​i​n​g​ ​o​n​e​ ​l​i​n​e​ ​i​n​s​t​a​l​l​:​ ​h​t​t​p​s​:​/​/​d​e​f​g​u​a​r​d​.​g​i​t​b​o​o​k​.​i​o​/​d​e​f​g​u​a​r​d​/​a​d​m​i​n​-​a​n​d​-​f​e​a​t​u​r​e​s​/​s​e​t​t​i​n​g​-​u​p​-​y​o​u​r​-​i​n​s​t​a​n​c​e​/​o​n​e​-​l​i​n​e​-​i​n​s​t​a​l​l​ ​ + * I​f​ ​y​o​u​ ​a​r​e​ ​d​o​i​n​g​ ​o​n​e​ ​l​i​n​e​ ​i​n​s​t​a​l​l​:​ ​h​t​t​p​s​:​/​/​d​e​f​g​u​a​r​d​.​g​i​t​b​o​o​k​.​i​o​/​d​e​f​g​u​a​r​d​/​a​d​m​i​n​-​a​n​d​-​f​e​a​t​u​r​e​s​/​s​e​t​t​i​n​g​-​u​p​-​y​o​u​r​-​i​n​s​t​a​n​c​e​/​o​n​e​-​l​i​n​e​-​i​n​s​t​a​l​l​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​y​o​u​ ​d​o​n​'​t​ ​n​e​e​d​ ​t​o​ ​d​o​ ​a​n​y​t​h​i​n​g​. */ oneLineInstall: string /** - * I​n​s​t​a​l​l​ ​t​h​e​ ​p​a​c​k​a​g​e​ ​a​v​a​i​l​a​b​l​e​ ​a​t​ ​h​t​t​p​s​:​/​/​g​i​t​h​u​b​.​c​o​m​/​D​e​f​G​u​a​r​d​/​g​a​t​e​w​a​y​/​r​e​l​e​a​s​e​s​/​l​a​t​e​s​t​ ​a​n​d​ ​c​o​n​f​i​g​u​r​e​ ​`​/​e​t​c​/​d​e​f​g​u​a​r​d​/​g​a​t​e​w​a​y​.​t​o​m​l​`​ ​ + * I​n​s​t​a​l​l​ ​t​h​e​ ​p​a​c​k​a​g​e​ ​a​v​a​i​l​a​b​l​e​ ​a​t​ ​h​t​t​p​s​:​/​/​g​i​t​h​u​b​.​c​o​m​/​D​e​f​G​u​a​r​d​/​g​a​t​e​w​a​y​/​r​e​l​e​a​s​e​s​/​l​a​t​e​s​t​ ​a​n​d​ ​c​o​n​f​i​g​u​r​e​ ​`​/​e​t​c​/​d​e​f​g​u​a​r​d​/​g​a​t​e​w​a​y​.​t​o​m​l​`​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​a​c​c​o​r​d​i​n​g​ ​t​o​ ​t​h​e​ ​[​d​o​c​u​m​e​n​t​a​t​i​o​n​]​(​{​s​e​t​u​p​G​a​t​e​w​a​y​D​o​c​s​}​)​. * @param {string} setupGatewayDocs */ fromPackage: RequiredParams<'setupGatewayDocs'> /** - * T​o​k​e​n​ ​b​e​l​o​w​ ​i​s​ ​r​e​q​u​i​r​e​d​ ​t​o​ ​a​u​t​h​e​n​t​i​c​a​t​e​ ​a​n​d​ ​c​o​n​f​i​g​u​r​e​ ​t​h​e​ ​g​a​t​e​w​a​y​ ​n​o​d​e​.​ ​E​n​s​u​r​e​ ​y​o​u​ ​k​e​e​p​ ​t​h​i​s​ ​t​o​k​e​n​ ​s​e​c​u​r​e​ ​a​n​d​ ​f​o​l​l​o​w​ ​t​h​e​ ​d​e​p​l​o​y​m​e​n​t​ ​i​n​s​t​r​u​c​t​i​o​n​s​ ​ + * T​o​k​e​n​ ​b​e​l​o​w​ ​i​s​ ​r​e​q​u​i​r​e​d​ ​t​o​ ​a​u​t​h​e​n​t​i​c​a​t​e​ ​a​n​d​ ​c​o​n​f​i​g​u​r​e​ ​t​h​e​ ​g​a​t​e​w​a​y​ ​n​o​d​e​.​ ​E​n​s​u​r​e​ ​y​o​u​ ​k​e​e​p​ ​t​h​i​s​ ​t​o​k​e​n​ ​s​e​c​u​r​e​ ​a​n​d​ ​f​o​l​l​o​w​ ​t​h​e​ ​d​e​p​l​o​y​m​e​n​t​ ​i​n​s​t​r​u​c​t​i​o​n​s​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​p​r​o​v​i​d​e​d​ ​i​n​ ​t​h​e​ ​[​d​o​c​u​m​e​n​t​a​t​i​o​n​]​(​{​s​e​t​u​p​G​a​t​e​w​a​y​D​o​c​s​}​)​ ​t​o​ ​s​u​c​c​e​s​s​f​u​l​l​y​ ​s​e​t​ ​u​p​ ​t​h​e​ ​g​a​t​e​w​a​y​ ​s​e​r​v​e​r​.​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​F​o​r​ ​m​o​r​e​ ​d​e​t​a​i​l​s​ ​a​n​d​ ​e​x​a​c​t​ ​s​t​e​p​s​,​ ​p​l​e​a​s​e​ ​r​e​f​e​r​ ​t​o​ ​t​h​e​ ​[​d​o​c​u​m​e​n​t​a​t​i​o​n​]​(​{​s​e​t​u​p​G​a​t​e​w​a​y​D​o​c​s​}​)​. * @param {string} setupGatewayDocs @@ -6474,6 +6496,10 @@ export type TranslationFunctions = { * This feature is available only in Defguard Enterprise. */ title: () => LocalizedString + /** + * Your current license has expired. + */ + currentExpired: () => LocalizedString /** * To learn more, visit our */ @@ -6882,6 +6908,24 @@ export type TranslationFunctions = { } } fields: { + status: { + /** + * Status + */ + label: () => LocalizedString + /** + * Active + */ + active: () => LocalizedString + /** + * Expired + */ + expired: () => LocalizedString + /** + * A subscription license is considered valid for some time after the expiration date to account for possible automatic payment delays. + */ + subscriptionHelper: () => LocalizedString + } type: { /** * Type @@ -7955,17 +7999,17 @@ export type TranslationFunctions = { */ statusError: () => LocalizedString /** - * If you are doing one line install: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install + * If you are doing one line install: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install you don't need to do anything. */ oneLineInstall: () => LocalizedString /** - * Install the package available at https://github.com/DefGuard/gateway/releases/latest and configure `/etc/defguard/gateway.toml` + * Install the package available at https://github.com/DefGuard/gateway/releases/latest and configure `/etc/defguard/gateway.toml` according to the [documentation]({setupGatewayDocs}). */ fromPackage: (arg: { setupGatewayDocs: string }) => LocalizedString /** - * Token below is required to authenticate and configure the gateway node. Ensure you keep this token secure and follow the deployment instructions + * Token below is required to authenticate and configure the gateway node. Ensure you keep this token secure and follow the deployment instructions provided in the [documentation]({setupGatewayDocs}) to successfully set up the gateway server. For more details and exact steps, please refer to the [documentation]({setupGatewayDocs}). */ diff --git a/web/src/i18n/pl/index.ts b/web/src/i18n/pl/index.ts index 201f23fc1..723d73afa 100644 --- a/web/src/i18n/pl/index.ts +++ b/web/src/i18n/pl/index.ts @@ -901,6 +901,7 @@ Uwaga, podane tutaj konfiguracje nie posiadają klucza prywatnego. Musisz uzupe }, enterpriseOnly: { title: 'Ta funkcja jest dostępna tylko w wersji Defguard Enterprise', + currentExpired: 'Twoja obecna licencja wygasła.', subtitle: 'Aby uzyskać więcej informacji, odwiedź naszą ', website: 'stronę internetową', }, @@ -1087,6 +1088,13 @@ Uwaga, podane tutaj konfiguracje nie posiadają klucza prywatnego. Musisz uzupe }, }, fields: { + status: { + label: 'Status', + active: 'Aktywna', + expired: 'Wygasła', + subscriptionHelper: + 'Licencja w formie subskrypcji jest ważna przez pewien czas po dacie wygaśnięcia, by uwzględnić możliwe opóźnienia w automatycznej płatności.', + }, type: { label: 'Typ', }, @@ -1562,14 +1570,14 @@ Uwaga, podane tutaj konfiguracje nie posiadają klucza prywatnego. Musisz uzupe noConnection: `Brak połączenia proszę uruchom poniższą komendę.`, connected: `Gateway połączony.`, statusError: 'Nie udało się uzyskać statusu', - oneLineInstall: `Jeśli wykonujesz instalację w jednej linii: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install + oneLineInstall: `Jeśli wykonujesz instalację w jednej linii: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install nie ma potrzeby wykonywania dalszych kroków.`, - fromPackage: `Zainstaluj pakiet dostępny na https://github.com/DefGuard/gateway/releases/latest i skonfiguruj \`/etc/defguard/gateway.toml\` + fromPackage: `Zainstaluj pakiet dostępny na https://github.com/DefGuard/gateway/releases/latest i skonfiguruj \`/etc/defguard/gateway.toml\` na podstawie [dokumentacji]({setupGatewayDocs}).`, - authToken: `Poniższy token jest wymwagany do autoryzacji i konfiguracji węzła gateway. Upewnij się, że zachowasz ten token w bezpiecznym miejscu, + authToken: `Poniższy token jest wymwagany do autoryzacji i konfiguracji węzła gateway. Upewnij się, że zachowasz ten token w bezpiecznym miejscu, a następnie podążaj za instrukcją wdrażania usługi znajdującej się w [dokumentacji]({setupGatewayDocs}), aby pomyślnie skonfigurwoać serwer gateway. Po więcej szczegółów i dokładnych kroków, proszę zapoznaj się z [dokumentacją](setupGatewayDocs).`, - dockerBasedGatewaySetup: `Poniżej znajduje się przykład oparty na Dockerze. + dockerBasedGatewaySetup: `Poniżej znajduje się przykład oparty na Dockerze. Więcej szczegółów i dokładnych kroków można znaleźć w [dokumentacji]({setupGatewayDocs}).`, }, }, diff --git a/web/src/pages/settings/components/EnterpriseSettings/EnterpriseSettings.tsx b/web/src/pages/settings/components/EnterpriseSettings/EnterpriseSettings.tsx index 3f658609e..af50d0056 100644 --- a/web/src/pages/settings/components/EnterpriseSettings/EnterpriseSettings.tsx +++ b/web/src/pages/settings/components/EnterpriseSettings/EnterpriseSettings.tsx @@ -3,16 +3,18 @@ import { useAppStore } from '../../../../shared/hooks/store/useAppStore'; import { EnterpriseForm } from './components/EnterpriseForm'; export const EnterpriseSettings = () => { - const enterpriseEnabled = useAppStore((state) => state.enterprise_status?.enabled); + const enterpriseStatus = useAppStore((state) => state.enterprise_status); const { LL } = useI18nContext(); const localLL = LL.settingsPage.enterpriseOnly; return ( <> - {!enterpriseEnabled && ( + {!enterpriseStatus?.enabled && (

{localLL.title()}

+ {/* If enterprise is disabled but we have some license info, the license probably expired */} + {enterpriseStatus?.license_info &&

{localLL.currentExpired()}

}

{localLL.subtitle()}{' '} diff --git a/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/LicenseSettings.tsx b/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/LicenseSettings.tsx index 99c1d1151..da16ed7af 100644 --- a/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/LicenseSettings.tsx +++ b/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/LicenseSettings.tsx @@ -12,6 +12,8 @@ import { useI18nContext } from '../../../../../../i18n/i18n-react'; import IconCheckmarkWhite from '../../../../../../shared/components/svg/IconCheckmarkWhite'; import { deviceBreakpoints } from '../../../../../../shared/constants'; import { FormInput } from '../../../../../../shared/defguard-ui/components/Form/FormInput/FormInput'; +import { ActivityIcon } from '../../../../../../shared/defguard-ui/components/icons/ActivityIcon/ActivityIcon'; +import { ActivityIconVariant } from '../../../../../../shared/defguard-ui/components/icons/ActivityIcon/types'; import { Button } from '../../../../../../shared/defguard-ui/components/Layout/Button/Button'; import { ButtonSize, @@ -44,7 +46,7 @@ export const LicenseSettings = () => { } = useApi(); const settings = useSettingsPage((state) => state.settings); - const licenseInfo = useAppStore((state) => state.enterprise_status?.license_info); + const enterpriseStatus = useAppStore((state) => state.enterprise_status); const queryClient = useQueryClient(); const { breakpoint } = useBreakpoint(deviceBreakpoints); @@ -133,18 +135,39 @@ export const LicenseSettings = () => { /> - {licenseInfo ? ( + {enterpriseStatus?.license_info ? (

+
+ + {enterpriseStatus?.enabled ? ( +
+ +

{LL.settingsPage.license.licenseInfo.fields.status.active()}

+ {enterpriseStatus?.license_info.subscription ? ( + + {LL.settingsPage.license.licenseInfo.fields.status.subscriptionHelper()} + + ) : null} +
+ ) : ( +
+ +

{LL.settingsPage.license.licenseInfo.fields.status.expired()}

+
+ )} +

- {licenseInfo.subscription + {enterpriseStatus?.license_info.subscription ? LL.settingsPage.license.licenseInfo.types.subscription.label() : LL.settingsPage.license.licenseInfo.types.offline.label()}

- {licenseInfo.subscription + {enterpriseStatus?.license_info.subscription ? LL.settingsPage.license.licenseInfo.types.subscription.helper() : LL.settingsPage.license.licenseInfo.types.offline.helper()} @@ -155,8 +178,10 @@ export const LicenseSettings = () => { {LL.settingsPage.license.licenseInfo.fields.validUntil.label()}

- {licenseInfo.valid_until - ? new Date(licenseInfo.valid_until).toLocaleString() + {enterpriseStatus?.license_info.valid_until + ? new Date( + enterpriseStatus?.license_info.valid_until, + ).toLocaleString() : '-'}

diff --git a/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/styles.scss b/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/styles.scss index 199810375..f874bb076 100644 --- a/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/styles.scss +++ b/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/styles.scss @@ -18,23 +18,27 @@ } #license-info { - display: flex; - flex-flow: row; - column-gap: 16px; - justify-content: space-evenly; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 16px; & > div { display: flex; flex-flow: column; row-gap: 8px; - - text-align: center; + align-items: center; & > .with-helper { display: flex; gap: 5px; } } + + .license-status { + display: flex; + align-items: center; + gap: 5px; + } } #no-license { diff --git a/web/src/pages/settings/components/OpenIdSettings/OpenIdSettings.tsx b/web/src/pages/settings/components/OpenIdSettings/OpenIdSettings.tsx index 9e8fd664e..8ba04f5bf 100644 --- a/web/src/pages/settings/components/OpenIdSettings/OpenIdSettings.tsx +++ b/web/src/pages/settings/components/OpenIdSettings/OpenIdSettings.tsx @@ -6,17 +6,19 @@ import { OpenIdGeneralSettings } from './components/OpenIdGeneralSettings'; import { OpenIdSettingsForm } from './components/OpenIdSettingsForm'; export const OpenIdSettings = () => { - const enterpriseEnabled = useAppStore((state) => state.enterprise_status?.enabled); + const enterpriseStatus = useAppStore((state) => state.enterprise_status); const { LL } = useI18nContext(); const localLL = LL.settingsPage.enterpriseOnly; return ( <> - {!enterpriseEnabled && ( + {!enterpriseStatus?.enabled && (