From f8aaf312c119d92ed0d9949e4315a4a1b1035e5f Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Mon, 6 Mar 2017 20:36:20 -0500 Subject: PLT-5703 Update license expiry timing and text (#5602) * Update license expiry timing and text * Updating error bar (#5632) --- utils/license.go | 2 + webapp/components/analytics/system_analytics.jsx | 32 ------------- webapp/components/error_bar.jsx | 61 +++++++++++++++++++----- webapp/i18n/en.json | 8 ++-- webapp/sass/components/_error-bar.scss | 35 +++++++++++++- webapp/utils/constants.jsx | 2 - webapp/utils/license_utils.jsx | 9 ++-- 7 files changed, 93 insertions(+), 56 deletions(-) diff --git a/utils/license.go b/utils/license.go index 2c43db6dd..5ec94386d 100644 --- a/utils/license.go +++ b/utils/license.go @@ -118,6 +118,7 @@ func getClientLicense(l *model.License) map[string]string { props["IsLicensed"] = strconv.FormatBool(IsLicensed) if IsLicensed { + props["Id"] = l.Id props["Users"] = strconv.Itoa(*l.Features.Users) props["LDAP"] = strconv.FormatBool(*l.Features.LDAP) props["MFA"] = strconv.FormatBool(*l.Features.MFA) @@ -166,6 +167,7 @@ func GetSanitizedClientLicense() map[string]string { } if IsLicensed { + delete(sanitizedLicense, "Id") delete(sanitizedLicense, "Name") delete(sanitizedLicense, "Email") delete(sanitizedLicense, "PhoneNumber") diff --git a/webapp/components/analytics/system_analytics.jsx b/webapp/components/analytics/system_analytics.jsx index a3517899a..5af055924 100644 --- a/webapp/components/analytics/system_analytics.jsx +++ b/webapp/components/analytics/system_analytics.jsx @@ -1,7 +1,6 @@ // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import Banner from 'components/admin_console/banner.jsx'; import LineChart from './line_chart.jsx'; import DoughnutChart from './doughnut_chart.jsx'; import StatisticCount from './statistic_count.jsx'; @@ -9,7 +8,6 @@ import StatisticCount from './statistic_count.jsx'; import AnalyticsStore from 'stores/analytics_store.jsx'; import * as Utils from 'utils/utils.jsx'; -import {isLicenseExpired, isLicenseExpiring, displayExpiryDate} from 'utils/license_utils.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; import Constants from 'utils/constants.jsx'; const StatTypes = Constants.StatTypes; @@ -287,36 +285,6 @@ class SystemAnalytics extends React.Component { {postTypeGraph} ); - - if (isLicenseExpired()) { - banner = ( - - } - /> - ); - } else if (isLicenseExpiring()) { - banner = ( - - } - /> - ); - } } const userCount = ( diff --git a/webapp/components/error_bar.jsx b/webapp/components/error_bar.jsx index 5fd12afc4..a1981aa2a 100644 --- a/webapp/components/error_bar.jsx +++ b/webapp/components/error_bar.jsx @@ -1,26 +1,37 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. +import AnalyticsStore from 'stores/analytics_store.jsx'; import ErrorStore from 'stores/error_store.jsx'; import UserStore from 'stores/user_store.jsx'; import * as Utils from 'utils/utils.jsx'; +import * as AsyncClient from 'utils/async_client.jsx'; import {isLicenseExpiring, isLicenseExpired, isLicensePastGracePeriod, displayExpiryDate} from 'utils/license_utils.jsx'; +import Constants from 'utils/constants.jsx'; +const StatTypes = Constants.StatTypes; import React from 'react'; -import {FormattedMessage} from 'react-intl'; +import {FormattedMessage, FormattedHTMLMessage} from 'react-intl'; const EXPIRING_ERROR = 'error_bar.expiring'; const EXPIRED_ERROR = 'error_bar.expired'; const PAST_GRACE_ERROR = 'error_bar.past_grace'; +const RENEWAL_LINK = 'https://licensing.mattermost.com/renew'; + +const BAR_DEVELOPER_TYPE = 'developer'; +const BAR_CRITICAL_TYPE = 'critical'; export default class ErrorBar extends React.Component { constructor() { super(); this.onErrorChange = this.onErrorChange.bind(this); + this.onAnalyticsChange = this.onAnalyticsChange.bind(this); this.handleClose = this.handleClose.bind(this); + ErrorStore.clearNotificationError(); + let isSystemAdmin = false; const user = UserStore.getCurrentUser(); if (user) { @@ -29,12 +40,16 @@ export default class ErrorBar extends React.Component { if (!ErrorStore.getIgnoreNotification() && global.window.mm_config.SendEmailNotifications === 'false') { ErrorStore.storeLastError({notification: true, message: Utils.localizeMessage('error_bar.preview_mode', 'Preview Mode: Email notifications have not been configured')}); + } else if (isLicensePastGracePeriod()) { + if (isSystemAdmin) { + ErrorStore.storeLastError({notification: true, message: EXPIRED_ERROR, type: BAR_CRITICAL_TYPE}); + } else { + ErrorStore.storeLastError({notification: true, message: PAST_GRACE_ERROR, type: BAR_CRITICAL_TYPE}); + } + } else if (isLicenseExpired() && isSystemAdmin) { + ErrorStore.storeLastError({notification: true, message: EXPIRED_ERROR, type: BAR_CRITICAL_TYPE}); } else if (isLicenseExpiring() && isSystemAdmin) { ErrorStore.storeLastError({notification: true, message: EXPIRING_ERROR}); - } else if (isLicenseExpired() && isSystemAdmin) { - ErrorStore.storeLastError({notification: true, message: EXPIRED_ERROR, type: 'developer'}); - } else if (isLicensePastGracePeriod()) { - ErrorStore.storeLastError({notification: true, message: PAST_GRACE_ERROR}); } this.state = ErrorStore.getLastError(); @@ -49,27 +64,41 @@ export default class ErrorBar extends React.Component { return false; } + if (s.message === EXPIRING_ERROR && !this.state.totalUsers) { + return false; + } + return true; } componentDidMount() { ErrorStore.addChangeListener(this.onErrorChange); + AnalyticsStore.addChangeListener(this.onAnalyticsChange); } componentWillUnmount() { ErrorStore.removeChangeListener(this.onErrorChange); + AnalyticsStore.removeChangeListener(this.onAnalyticsChange); } onErrorChange() { var newState = ErrorStore.getLastError(); if (newState) { + if (newState.message === EXPIRING_ERROR && !this.state.totalUsers) { + AsyncClient.getStandardAnalytics(); + } this.setState(newState); } else { this.setState({message: null}); } } + onAnalyticsChange() { + const stats = AnalyticsStore.getAllSystem(); + this.setState({totalUsers: stats[StatTypes.TOTAL_USERS]}); + } + handleClose(e) { if (e) { e.preventDefault(); @@ -91,33 +120,41 @@ export default class ErrorBar extends React.Component { var errClass = 'error-bar'; - if (this.state.type && this.state.type === 'developer') { + if (this.state.type === BAR_DEVELOPER_TYPE) { errClass = 'error-bar-developer'; + } else if (this.state.type === BAR_CRITICAL_TYPE) { + errClass = 'error-bar-critical'; } + const renewalLink = RENEWAL_LINK + '?id=' + global.window.mm_license.Id + '&user_count=' + this.state.totalUsers; + let message = this.state.message; if (message === EXPIRING_ERROR) { message = ( - ); } else if (message === EXPIRED_ERROR) { message = ( - ); } else if (message === PAST_GRACE_ERROR) { message = ( ); } diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 6841660cf..cf04ccc0e 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -941,8 +941,6 @@ "analytics.system.activeUsers": "Active Users With Posts", "analytics.system.channelTypes": "Channel Types", "analytics.system.dailyActiveUsers": "Daily Active Users", - "analytics.system.expiredBanner": "The Enterprise license expired on {date}. You have 15 days from this date to renew the license, please contact commercial@mattermost.com.", - "analytics.system.expiringBanner": "The Enterprise license is expiring on {date}. To renew your license, please contact commercial@mattermost.com.", "analytics.system.monthlyActiveUsers": "Monthly Active Users", "analytics.system.postTypes": "Posts, Files and Hashtags", "analytics.system.privateGroups": "Private Groups", @@ -1293,9 +1291,9 @@ "error.not_found.title": "Page not found", "error.not_supported.message": "Private browsing is not supported", "error.not_supported.title": "Browser not supported", - "error_bar.expired": "Enterprise license has expired; you have 15 days from expiry to renew the license, please contact commercial@mattermost.com for details", - "error_bar.expiring": "The Enterprise license is expiring on {date}. To renew your license, please contact commercial@mattermost.com", - "error_bar.past_grace": "Enterprise license has expired, please contact your System Administrator for details", + "error_bar.expired": "Enterprise license is expired and some features may be disabled. Please renew.", + "error_bar.expiring": "Enterprise license expires on {date}. Please renew.", + "error_bar.past_grace": "Enterprise license is expired and some features may be disabled. Please contact your System Administrator for details.", "error_bar.preview_mode": "Preview Mode: Email notifications have not been configured", "file_attachment.download": "Download", "file_info_preview.size": "Size ", diff --git a/webapp/sass/components/_error-bar.scss b/webapp/sass/components/_error-bar.scss index 2791337c4..c2ad2402a 100644 --- a/webapp/sass/components/_error-bar.scss +++ b/webapp/sass/components/_error-bar.scss @@ -11,6 +11,9 @@ z-index: 9999; a { + color: $white !important; + text-decoration: underline; + &.error-bar__close { color: $white; font-family: 'Open Sans', sans-serif; @@ -30,7 +33,7 @@ } } -.error-bar-developer { +.error-bar-critical { background-color: #B0171F; color: white; padding: 5px 30px; @@ -59,3 +62,33 @@ } } } + +.error-bar-developer { + background-color: purple; + color: white; + padding: 5px 30px; + position: absolute; + text-align: center; + top: 0; + width: 100%; + z-index: 9999; + + a { + &.error-bar__close { + color: $white; + font-family: 'Open Sans', sans-serif; + font-size: 20px; + font-weight: 600; + padding: 0 10px; + position: absolute; + right: 0; + text-decoration: none; + top: 0; + + &:hover { + color: $white; + text-decoration: none; + } + } + } +} diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx index fafad9f44..cb55da9b8 100644 --- a/webapp/utils/constants.jsx +++ b/webapp/utils/constants.jsx @@ -885,8 +885,6 @@ export const Constants = { BOT_NAME: 'BOT', MAX_PREV_MSGS: 100, POST_COLLAPSE_TIMEOUT: 1000 * 60 * 5, // five minutes - LICENSE_EXPIRY_NOTIFICATION: 1000 * 60 * 60 * 24 * 15, // 15 days - LICENSE_GRACE_PERIOD: 1000 * 60 * 60 * 24 * 15, // 15 days PERMISSIONS_ALL: 'all', PERMISSIONS_CHANNEL_ADMIN: 'channel_admin', PERMISSIONS_TEAM_ADMIN: 'team_admin', diff --git a/webapp/utils/license_utils.jsx b/webapp/utils/license_utils.jsx index c4be1f25e..038e3ca29 100644 --- a/webapp/utils/license_utils.jsx +++ b/webapp/utils/license_utils.jsx @@ -1,17 +1,18 @@ // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import Constants from 'utils/constants.jsx'; - import LocalizationStore from 'stores/localization_store.jsx'; +const LICENSE_EXPIRY_NOTIFICATION = 1000 * 60 * 60 * 24 * 60; // 60 days +const LICENSE_GRACE_PERIOD = 1000 * 60 * 60 * 24 * 15; // 15 days + export function isLicenseExpiring() { if (window.mm_license.IsLicensed !== 'true') { return false; } const timeDiff = parseInt(global.window.mm_license.ExpiresAt, 10) - Date.now(); - return timeDiff <= Constants.LICENSE_EXPIRY_NOTIFICATION; + return timeDiff <= LICENSE_EXPIRY_NOTIFICATION; } export function isLicenseExpired() { @@ -29,7 +30,7 @@ export function isLicensePastGracePeriod() { } const timeDiff = Date.now() - parseInt(global.window.mm_license.ExpiresAt, 10); - return timeDiff > Constants.LICENSE_GRACE_PERIOD; + return timeDiff > LICENSE_GRACE_PERIOD; } export function displayExpiryDate() { -- cgit v1.2.3-1-g7c22