mirror of
https://github.com/mattermost/mattermost.git
synced 2026-09-24 16:05:00 +08:00
Team Edition User Limit Update (#33888)
* Lower user limit for TE to final limit * Added warning banner for user soft limit * Linting * Fix test * Fix tests
This commit is contained in:
@@ -29,8 +29,8 @@ func TestGetServerLimits(t *testing.T) {
|
||||
|
||||
// Should have full access to all limits data
|
||||
require.Greater(t, serverLimits.ActiveUserCount, int64(0))
|
||||
require.Equal(t, int64(2500), serverLimits.MaxUsersLimit)
|
||||
require.Equal(t, int64(5000), serverLimits.MaxUsersHardLimit)
|
||||
require.Equal(t, int64(200), serverLimits.MaxUsersLimit)
|
||||
require.Equal(t, int64(250), serverLimits.MaxUsersHardLimit)
|
||||
require.Equal(t, int64(0), serverLimits.PostHistoryLimit)
|
||||
require.Equal(t, int64(0), serverLimits.LastAccessiblePostTime)
|
||||
})
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
maxUsersLimit = 2_500
|
||||
maxUsersHardLimit = 5_000
|
||||
maxUsersLimit = 200
|
||||
maxUsersHardLimit = 250
|
||||
)
|
||||
|
||||
func (a *App) GetServerLimits() (*model.ServerLimits, *model.AppError) {
|
||||
|
||||
@@ -28,8 +28,8 @@ func TestGetServerLimits(t *testing.T) {
|
||||
|
||||
// InitBasic creates 3 users by default
|
||||
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
|
||||
require.Equal(t, int64(2500), serverLimits.MaxUsersLimit)
|
||||
require.Equal(t, int64(5000), serverLimits.MaxUsersHardLimit)
|
||||
require.Equal(t, int64(200), serverLimits.MaxUsersLimit)
|
||||
require.Equal(t, int64(250), serverLimits.MaxUsersHardLimit)
|
||||
})
|
||||
|
||||
t.Run("user count should increase on creating new user and decrease on permanently deleting", func(t *testing.T) {
|
||||
@@ -279,7 +279,7 @@ func TestIsAtUserLimit(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
mockUserStore := storemocks.UserStore{}
|
||||
mockUserStore.On("Count", mock.Anything).Return(int64(4000), nil) // Under hard limit of 5000
|
||||
mockUserStore.On("Count", mock.Anything).Return(int64(200), nil) // Under hard limit of 250
|
||||
mockStore := th.App.Srv().Store().(*storemocks.Store)
|
||||
mockStore.On("User").Return(&mockUserStore)
|
||||
|
||||
@@ -295,7 +295,7 @@ func TestIsAtUserLimit(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
mockUserStore := storemocks.UserStore{}
|
||||
mockUserStore.On("Count", mock.Anything).Return(int64(5000), nil) // At hard limit of 5000
|
||||
mockUserStore.On("Count", mock.Anything).Return(int64(250), nil) // At hard limit of 250
|
||||
mockStore := th.App.Srv().Store().(*storemocks.Store)
|
||||
mockStore.On("User").Return(&mockUserStore)
|
||||
|
||||
@@ -311,7 +311,7 @@ func TestIsAtUserLimit(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
mockUserStore := storemocks.UserStore{}
|
||||
mockUserStore.On("Count", mock.Anything).Return(int64(6000), nil) // Over hard limit of 5000
|
||||
mockUserStore.On("Count", mock.Anything).Return(int64(300), nil) // Over hard limit of 250
|
||||
mockStore := th.App.Srv().Store().(*storemocks.Store)
|
||||
mockStore.On("User").Return(&mockUserStore)
|
||||
|
||||
@@ -547,8 +547,8 @@ func TestExtraUsersBehavior(t *testing.T) {
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// Unlicensed servers use hard-coded limits without extra users
|
||||
require.Equal(t, int64(2500), serverLimits.MaxUsersLimit)
|
||||
require.Equal(t, int64(5000), serverLimits.MaxUsersHardLimit)
|
||||
require.Equal(t, int64(200), serverLimits.MaxUsersLimit)
|
||||
require.Equal(t, int64(250), serverLimits.MaxUsersHardLimit)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -149,6 +149,8 @@ export default class AnnouncementBar extends React.PureComponent<Props, State> {
|
||||
barClass = 'announcement-bar announcement-bar-advisor-ack';
|
||||
} else if (this.props.type === AnnouncementBarTypes.GENERAL) {
|
||||
barClass = 'announcement-bar announcement-bar-general';
|
||||
} else if (this.props.type === AnnouncementBarTypes.WARNING) {
|
||||
barClass = 'announcement-bar announcement-bar-warning';
|
||||
}
|
||||
|
||||
if (this.props.className) {
|
||||
|
||||
+141
-44
@@ -1,88 +1,185 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {shouldShowUserLimitsAnnouncementBar} from './index';
|
||||
import {shouldShowCriticalBanner, shouldShowWarningBanner} from './index';
|
||||
import type {ShouldShowingUserLimitsAnnouncementBarProps} from './index';
|
||||
|
||||
describe('shouldShowUserLimitsAnnouncementBar', () => {
|
||||
const defaultProps: ShouldShowingUserLimitsAnnouncementBarProps = {
|
||||
describe('shouldShowCriticalBanner', () => {
|
||||
const defaultCriticalProps: ShouldShowingUserLimitsAnnouncementBarProps = {
|
||||
userIsAdmin: true,
|
||||
isLicensed: false,
|
||||
maxUsersLimit: 10,
|
||||
activeUserCount: 5,
|
||||
maxUsersHardLimit: 20,
|
||||
activeUserCount: 15,
|
||||
};
|
||||
|
||||
test('should not show when user is not admin', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
...defaultCriticalProps,
|
||||
userIsAdmin: false,
|
||||
};
|
||||
expect(shouldShowUserLimitsAnnouncementBar(props)).toBe(false);
|
||||
expect(shouldShowCriticalBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when active users count is 0', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
...defaultCriticalProps,
|
||||
activeUserCount: 0,
|
||||
};
|
||||
expect(shouldShowUserLimitsAnnouncementBar(props)).toBe(false);
|
||||
expect(shouldShowCriticalBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when max users limit is 0', () => {
|
||||
test('should not show when max users hard limit is 0', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
maxUsersLimit: 0,
|
||||
...defaultCriticalProps,
|
||||
maxUsersHardLimit: 0,
|
||||
};
|
||||
expect(shouldShowUserLimitsAnnouncementBar(props)).toBe(false);
|
||||
expect(shouldShowCriticalBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when active users count is less than max users limit', () => {
|
||||
test('should not show when active users count is less than max users hard limit', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
activeUserCount: 5,
|
||||
maxUsersLimit: 10,
|
||||
};
|
||||
expect(shouldShowUserLimitsAnnouncementBar(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should show when active users count is equal to max users limit', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
activeUserCount: 10,
|
||||
maxUsersLimit: 10,
|
||||
};
|
||||
expect(shouldShowUserLimitsAnnouncementBar(props)).toBe(true);
|
||||
});
|
||||
|
||||
test('should show for non licensed servers with active users count is greater than max users limit', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
isLicensed: false,
|
||||
...defaultCriticalProps,
|
||||
activeUserCount: 15,
|
||||
maxUsersLimit: 10,
|
||||
maxUsersHardLimit: 20,
|
||||
};
|
||||
expect(shouldShowUserLimitsAnnouncementBar(props)).toBe(true);
|
||||
expect(shouldShowCriticalBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should show when active users count is equal to max users hard limit', () => {
|
||||
const props = {
|
||||
...defaultCriticalProps,
|
||||
activeUserCount: 20,
|
||||
maxUsersHardLimit: 20,
|
||||
};
|
||||
expect(shouldShowCriticalBanner(props)).toBe(true);
|
||||
});
|
||||
|
||||
test('should show for non licensed servers with active users count is greater than max users hard limit', () => {
|
||||
const props = {
|
||||
...defaultCriticalProps,
|
||||
isLicensed: false,
|
||||
activeUserCount: 25,
|
||||
maxUsersHardLimit: 20,
|
||||
};
|
||||
expect(shouldShowCriticalBanner(props)).toBe(true);
|
||||
});
|
||||
|
||||
test('should not show for licensed server', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
...defaultCriticalProps,
|
||||
isLicensed: true,
|
||||
activeUserCount: 0,
|
||||
maxUsersLimit: 0,
|
||||
maxUsersHardLimit: 0,
|
||||
};
|
||||
|
||||
expect(shouldShowUserLimitsAnnouncementBar(props)).toBe(false);
|
||||
expect(shouldShowCriticalBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show for licensed server even if user count is greater than max users limit', () => {
|
||||
test('should not show for licensed server even if user count is greater than max users hard limit', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
...defaultCriticalProps,
|
||||
isLicensed: true,
|
||||
activeUserCount: 101,
|
||||
maxUsersLimit: 100,
|
||||
activeUserCount: 25,
|
||||
maxUsersHardLimit: 20,
|
||||
};
|
||||
|
||||
expect(shouldShowUserLimitsAnnouncementBar(props)).toBe(false);
|
||||
expect(shouldShowCriticalBanner(props)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldShowWarningBanner', () => {
|
||||
const defaultWarningProps: ShouldShowingUserLimitsAnnouncementBarProps = {
|
||||
userIsAdmin: true,
|
||||
isLicensed: false,
|
||||
maxUsersLimit: 10,
|
||||
maxUsersHardLimit: 20,
|
||||
activeUserCount: 12,
|
||||
isWarningDismissed: false,
|
||||
};
|
||||
|
||||
test('should not show when user is not admin', () => {
|
||||
const props = {
|
||||
...defaultWarningProps,
|
||||
userIsAdmin: false,
|
||||
};
|
||||
expect(shouldShowWarningBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when active users count is 0', () => {
|
||||
const props = {
|
||||
...defaultWarningProps,
|
||||
activeUserCount: 0,
|
||||
};
|
||||
expect(shouldShowWarningBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when max users limit is 0', () => {
|
||||
const props = {
|
||||
...defaultWarningProps,
|
||||
maxUsersLimit: 0,
|
||||
};
|
||||
expect(shouldShowWarningBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when max users hard limit is 0', () => {
|
||||
const props = {
|
||||
...defaultWarningProps,
|
||||
maxUsersHardLimit: 0,
|
||||
};
|
||||
expect(shouldShowWarningBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when warning is dismissed', () => {
|
||||
const props = {
|
||||
...defaultWarningProps,
|
||||
isWarningDismissed: true,
|
||||
};
|
||||
expect(shouldShowWarningBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when active users count is less than max users limit', () => {
|
||||
const props = {
|
||||
...defaultWarningProps,
|
||||
activeUserCount: 8,
|
||||
maxUsersLimit: 10,
|
||||
};
|
||||
expect(shouldShowWarningBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when active users count is greater than or equal to max users hard limit', () => {
|
||||
const props = {
|
||||
...defaultWarningProps,
|
||||
activeUserCount: 20,
|
||||
maxUsersHardLimit: 20,
|
||||
};
|
||||
expect(shouldShowWarningBanner(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should show when active users count is between max users limit and max users hard limit', () => {
|
||||
const props = {
|
||||
...defaultWarningProps,
|
||||
activeUserCount: 15,
|
||||
maxUsersLimit: 10,
|
||||
maxUsersHardLimit: 20,
|
||||
};
|
||||
expect(shouldShowWarningBanner(props)).toBe(true);
|
||||
});
|
||||
|
||||
test('should show when active users count equals max users limit', () => {
|
||||
const props = {
|
||||
...defaultWarningProps,
|
||||
activeUserCount: 10,
|
||||
maxUsersLimit: 10,
|
||||
maxUsersHardLimit: 20,
|
||||
};
|
||||
expect(shouldShowWarningBanner(props)).toBe(true);
|
||||
});
|
||||
|
||||
test('should not show for licensed server', () => {
|
||||
const props = {
|
||||
...defaultWarningProps,
|
||||
isLicensed: true,
|
||||
};
|
||||
expect(shouldShowWarningBanner(props)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
+113
-34
@@ -3,16 +3,22 @@
|
||||
|
||||
import React, {useCallback} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {useSelector} from 'react-redux';
|
||||
import {useDispatch, useSelector} from 'react-redux';
|
||||
|
||||
import {AlertOutlineIcon} from '@mattermost/compass-icons/components';
|
||||
import type {ClientLicense} from '@mattermost/types/config';
|
||||
import type {PreferenceType} from '@mattermost/types/preferences';
|
||||
|
||||
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||
import {getServerLimits} from 'mattermost-redux/selectors/entities/limits';
|
||||
import {get as getPreference} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import AnnouncementBar from 'components/announcement_bar/default_announcement_bar';
|
||||
|
||||
import {AnnouncementBarTypes} from 'utils/constants';
|
||||
import {AnnouncementBarTypes, Preferences} from 'utils/constants';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
type Props = {
|
||||
license?: ClientLicense;
|
||||
@@ -22,7 +28,9 @@ type Props = {
|
||||
const learnMoreExternalLink = 'https://mattermost.com/pl/error-code-error-safety-limits-exceeded';
|
||||
|
||||
function UsersLimitsAnnouncementBar(props: Props) {
|
||||
const dispatch = useDispatch();
|
||||
const serverLimits = useSelector(getServerLimits);
|
||||
const currentUser = useSelector(getCurrentUser);
|
||||
|
||||
const handleCTAClick = useCallback(() => {
|
||||
window.open(learnMoreExternalLink, '_blank');
|
||||
@@ -30,57 +38,128 @@ function UsersLimitsAnnouncementBar(props: Props) {
|
||||
|
||||
const isLicensed = props?.license?.IsLicensed === 'true';
|
||||
const maxUsersLimit = serverLimits?.maxUsersLimit ?? 0;
|
||||
const maxUsersHardLimit = serverLimits?.maxUsersHardLimit ?? 0;
|
||||
const activeUserCount = serverLimits?.activeUserCount ?? 0;
|
||||
|
||||
if (!shouldShowUserLimitsAnnouncementBar({userIsAdmin: props.userIsAdmin, isLicensed, maxUsersLimit, activeUserCount})) {
|
||||
return null;
|
||||
// Check if warning banner has been dismissed
|
||||
const warningDismissalKey = 'users_limits_warning';
|
||||
const isWarningDismissed = useSelector((state: GlobalState) => {
|
||||
return getPreference(state, Preferences.USERS_LIMITS_BANNER, warningDismissalKey, 'false') === 'true';
|
||||
});
|
||||
|
||||
const handleWarningDismiss = useCallback(() => {
|
||||
if (currentUser?.id) {
|
||||
const preference: PreferenceType = {
|
||||
category: Preferences.USERS_LIMITS_BANNER,
|
||||
name: warningDismissalKey,
|
||||
user_id: currentUser.id,
|
||||
value: 'true',
|
||||
};
|
||||
dispatch(savePreferences(currentUser.id, [preference]));
|
||||
}
|
||||
}, [currentUser?.id, dispatch, warningDismissalKey]);
|
||||
|
||||
// Critical state: activeUserCount >= hardLimit
|
||||
if (shouldShowCriticalBanner({userIsAdmin: props.userIsAdmin, isLicensed, maxUsersHardLimit, activeUserCount})) {
|
||||
return (
|
||||
<AnnouncementBar
|
||||
id='users_limits_announcement_bar_critical'
|
||||
showCloseButton={false}
|
||||
message={
|
||||
<FormattedMessage
|
||||
id='users_limits_announcement_bar.copyText'
|
||||
defaultMessage='User limits exceeded. Contact administrator with: {ErrorCode}'
|
||||
values={{
|
||||
ErrorCode: 'ERROR_SAFETY_LIMITS_EXCEEDED',
|
||||
}}
|
||||
/>
|
||||
}
|
||||
type={AnnouncementBarTypes.CRITICAL}
|
||||
icon={<AlertOutlineIcon size={16}/>}
|
||||
showCTA={true}
|
||||
showLinkAsButton={true}
|
||||
ctaText={
|
||||
<FormattedMessage
|
||||
id='users_limits_announcement_bar.ctaText'
|
||||
defaultMessage='Learn More'
|
||||
/>
|
||||
}
|
||||
onButtonClick={handleCTAClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AnnouncementBar
|
||||
id='users_limits_announcement_bar'
|
||||
showCloseButton={false}
|
||||
message={
|
||||
<FormattedMessage
|
||||
id='users_limits_announcement_bar.copyText'
|
||||
defaultMessage='User limits exceeded. Contact administrator with: {ErrorCode}'
|
||||
values={{
|
||||
ErrorCode: 'ERROR_SAFETY_LIMITS_EXCEEDED',
|
||||
}}
|
||||
/>
|
||||
}
|
||||
type={AnnouncementBarTypes.CRITICAL}
|
||||
icon={<AlertOutlineIcon size={16}/>}
|
||||
showCTA={true}
|
||||
showLinkAsButton={true}
|
||||
ctaText={
|
||||
<FormattedMessage
|
||||
id='users_limits_announcement_bar.ctaText'
|
||||
defaultMessage='Learn More'
|
||||
/>
|
||||
}
|
||||
onButtonClick={handleCTAClick}
|
||||
/>
|
||||
);
|
||||
// Warning state: activeUserCount >= maxLimit && < hardLimit
|
||||
if (shouldShowWarningBanner({userIsAdmin: props.userIsAdmin, isLicensed, maxUsersLimit, maxUsersHardLimit, activeUserCount, isWarningDismissed})) {
|
||||
return (
|
||||
<AnnouncementBar
|
||||
id='users_limits_announcement_bar_warning'
|
||||
showCloseButton={true}
|
||||
handleClose={handleWarningDismiss}
|
||||
message={
|
||||
<FormattedMessage
|
||||
id='users_limits_announcement_bar.warning.copyText'
|
||||
defaultMessage='This workspace is approaching the user limit ({activeUserCount}/{maxUsersHardLimit} users).'
|
||||
values={{
|
||||
activeUserCount,
|
||||
maxUsersHardLimit,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
type='warning'
|
||||
icon={<AlertOutlineIcon size={16}/>}
|
||||
showCTA={true}
|
||||
showLinkAsButton={true}
|
||||
ctaText={
|
||||
<FormattedMessage
|
||||
id='users_limits_announcement_bar.ctaText'
|
||||
defaultMessage='Learn More'
|
||||
/>
|
||||
}
|
||||
onButtonClick={handleCTAClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export type ShouldShowingUserLimitsAnnouncementBarProps = {
|
||||
userIsAdmin: boolean;
|
||||
isLicensed: boolean;
|
||||
maxUsersLimit: number;
|
||||
maxUsersLimit?: number;
|
||||
maxUsersHardLimit: number;
|
||||
activeUserCount: number;
|
||||
isWarningDismissed?: boolean;
|
||||
};
|
||||
|
||||
export function shouldShowUserLimitsAnnouncementBar({userIsAdmin, isLicensed, maxUsersLimit, activeUserCount}: ShouldShowingUserLimitsAnnouncementBarProps) {
|
||||
export function shouldShowCriticalBanner({userIsAdmin, isLicensed, maxUsersHardLimit, activeUserCount}: ShouldShowingUserLimitsAnnouncementBarProps) {
|
||||
if (!userIsAdmin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (maxUsersLimit === 0 || activeUserCount === 0) {
|
||||
if (maxUsersHardLimit === 0 || activeUserCount === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !isLicensed && activeUserCount >= maxUsersLimit;
|
||||
return !isLicensed && activeUserCount >= maxUsersHardLimit;
|
||||
}
|
||||
|
||||
export function shouldShowWarningBanner({userIsAdmin, isLicensed, maxUsersLimit = 0, maxUsersHardLimit, activeUserCount, isWarningDismissed}: ShouldShowingUserLimitsAnnouncementBarProps) {
|
||||
if (!userIsAdmin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (maxUsersLimit === 0 || maxUsersHardLimit === 0 || activeUserCount === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isWarningDismissed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Show warning when users >= maxUsersLimit but < maxUsersHardLimit
|
||||
return !isLicensed && activeUserCount >= maxUsersLimit && activeUserCount < maxUsersHardLimit;
|
||||
}
|
||||
|
||||
export default UsersLimitsAnnouncementBar;
|
||||
|
||||
@@ -6438,6 +6438,7 @@
|
||||
"userGuideHelp.trainingResources": "Training resources",
|
||||
"users_limits_announcement_bar.copyText": "User limits exceeded. Contact administrator with: {ErrorCode}",
|
||||
"users_limits_announcement_bar.ctaText": "Learn More",
|
||||
"users_limits_announcement_bar.warning.copyText": "This workspace is approaching the user limit ({activeUserCount}/{maxUsersHardLimit} users).",
|
||||
"userSettings.adminMode.admin_mode_badge": "Admin Mode",
|
||||
"userSettings.adminMode.modal_header": "Manage {userDisplayName}'s Settings",
|
||||
"userSettingsModal.pluginPreferences.header": "PLUGIN PREFERENCES",
|
||||
|
||||
@@ -121,6 +121,18 @@
|
||||
background-color: #3d3c40;
|
||||
}
|
||||
|
||||
.announcement-bar-warning {
|
||||
background-color: var(--yellow-400);
|
||||
color: var(--neutral-900);
|
||||
.announcement-bar__text {
|
||||
.btn.btn-tertiary.btn-xs.btn-inverted {
|
||||
border-color: var(--neutral-900);
|
||||
|
||||
color: var(--neutral-900);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.announcement-bar__link {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
@@ -151,6 +151,7 @@ export const Preferences = {
|
||||
NOTIFY_ADMIN_REVOKE_DOWNGRADED_WORKSPACE: 'admin_revoke_downgraded_instance',
|
||||
OVERAGE_USERS_BANNER: ReduxPreferences.CATEGORY_OVERAGE_USERS_BANNER,
|
||||
POST_HISTORY_LIMIT_BANNER: ReduxPreferences.CATEGORY_POST_HISTORY_LIMIT_BANNER,
|
||||
USERS_LIMITS_BANNER: 'users_limits_banner',
|
||||
TO_CLOUD_YEARLY_PLAN_NUDGE: 'to_cloud_yearly_plan_nudge',
|
||||
TO_PAID_PLAN_NUDGE: 'to_paid_plan_nudge',
|
||||
CLOUD_ANNUAL_RENEWAL_BANNER: 'cloud_annual_renewal_banner',
|
||||
@@ -932,6 +933,7 @@ export const AnnouncementBarTypes = {
|
||||
ADVISOR: 'advisor',
|
||||
ADVISOR_ACK: 'advisor-ack',
|
||||
GENERAL: 'general',
|
||||
WARNING: 'warning',
|
||||
};
|
||||
|
||||
export const AnnouncementBarMessages = {
|
||||
|
||||
Reference in New Issue
Block a user