Fix license upload when already set by env variable (#30974)

* Fix license upload when already set by env variable

* Add tooltip

* Fix tests and texts

* Fix snapshots

* Add disabled styles to secondary button

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Daniel Espino García
2025-06-13 13:07:20 +02:00
коммит произвёл GitHub
родитель 43018759e5
Коммит 0376bc7cc1
7 изменённых файлов: 48 добавлений и 11 удалений

Просмотреть файл

@@ -310,6 +310,7 @@ exports[`components/admin_console/license_settings/LicenseSettings should match
handleChange={[Function]} handleChange={[Function]}
handleRemove={[Function]} handleRemove={[Function]}
isDisabled={false} isDisabled={false}
isLicenseSetByEnvVar={false}
isTrialLicense={false} isTrialLicense={false}
license={ license={
Object { Object {
@@ -461,6 +462,7 @@ exports[`components/admin_console/license_settings/LicenseSettings should match
handleChange={[Function]} handleChange={[Function]}
handleRemove={[Function]} handleRemove={[Function]}
isDisabled={false} isDisabled={false}
isLicenseSetByEnvVar={false}
isTrialLicense={false} isTrialLicense={false}
license={ license={
Object { Object {
@@ -600,6 +602,7 @@ exports[`components/admin_console/license_settings/LicenseSettings should match
handleChange={[Function]} handleChange={[Function]}
handleRemove={[Function]} handleRemove={[Function]}
isDisabled={false} isDisabled={false}
isLicenseSetByEnvVar={false}
isTrialLicense={false} isTrialLicense={false}
license={ license={
Object { Object {
@@ -739,6 +742,7 @@ exports[`components/admin_console/license_settings/LicenseSettings should match
handleChange={[Function]} handleChange={[Function]}
handleRemove={[Function]} handleRemove={[Function]}
isDisabled={false} isDisabled={false}
isLicenseSetByEnvVar={false}
isTrialLicense={false} isTrialLicense={false}
license={ license={
Object { Object {
@@ -878,6 +882,7 @@ exports[`components/admin_console/license_settings/LicenseSettings should match
handleChange={[Function]} handleChange={[Function]}
handleRemove={[Function]} handleRemove={[Function]}
isDisabled={true} isDisabled={true}
isLicenseSetByEnvVar={false}
isTrialLicense={false} isTrialLicense={false}
license={ license={
Object { Object {
@@ -1017,6 +1022,7 @@ exports[`components/admin_console/license_settings/LicenseSettings should match
handleChange={[Function]} handleChange={[Function]}
handleRemove={[Function]} handleRemove={[Function]}
isDisabled={false} isDisabled={false}
isLicenseSetByEnvVar={false}
isTrialLicense={false} isTrialLicense={false}
license={ license={
Object { Object {
@@ -1146,6 +1152,7 @@ exports[`components/admin_console/license_settings/LicenseSettings should match
handleChange={[Function]} handleChange={[Function]}
handleRemove={[Function]} handleRemove={[Function]}
isDisabled={false} isDisabled={false}
isLicenseSetByEnvVar={false}
isTrialLicense={true} isTrialLicense={true}
license={ license={
Object { Object {
@@ -1846,6 +1853,7 @@ exports[`components/admin_console/license_settings/LicenseSettings should match
handleChange={[Function]} handleChange={[Function]}
handleRemove={[Function]} handleRemove={[Function]}
isDisabled={false} isDisabled={false}
isLicenseSetByEnvVar={false}
isTrialLicense={false} isTrialLicense={false}
license={ license={
Object { Object {
@@ -1987,6 +1995,7 @@ exports[`components/admin_console/license_settings/LicenseSettings should match
handleChange={[Function]} handleChange={[Function]}
handleRemove={[Function]} handleRemove={[Function]}
isDisabled={false} isDisabled={false}
isLicenseSetByEnvVar={false}
isTrialLicense={false} isTrialLicense={false}
license={ license={
Object { Object {

Просмотреть файл

@@ -94,6 +94,7 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris
handleChange: jest.fn(), handleChange: jest.fn(),
fileInputRef: React.createRef(), fileInputRef: React.createRef(),
statsActiveUsers: 1, statsActiveUsers: 1,
isLicenseSetByEnvVar: false,
}; };
test('should format the Users field', () => { test('should format the Users field', () => {

Просмотреть файл

@@ -4,7 +4,7 @@
import classNames from 'classnames'; import classNames from 'classnames';
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import type {RefObject} from 'react'; import type {RefObject} from 'react';
import {FormattedDate, FormattedMessage, FormattedNumber, FormattedTime, defineMessages, useIntl} from 'react-intl'; import {FormattedDate, FormattedMessage, FormattedNumber, FormattedTime, defineMessage, defineMessages, useIntl} from 'react-intl';
import type {ClientLicense} from '@mattermost/types/config'; import type {ClientLicense} from '@mattermost/types/config';
@@ -13,6 +13,7 @@ import {Client4} from 'mattermost-redux/client';
import useOpenPricingModal from 'components/common/hooks/useOpenPricingModal'; import useOpenPricingModal from 'components/common/hooks/useOpenPricingModal';
import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink';
import Tag from 'components/widgets/tag/tag'; import Tag from 'components/widgets/tag/tag';
import WithTooltip from 'components/with_tooltip';
import {FileTypes} from 'utils/constants'; import {FileTypes} from 'utils/constants';
import {calculateOverageUserActivated} from 'utils/overage_team'; import {calculateOverageUserActivated} from 'utils/overage_team';
@@ -35,6 +36,7 @@ export interface EnterpriseEditionProps {
fileInputRef: RefObject<HTMLInputElement>; fileInputRef: RefObject<HTMLInputElement>;
handleChange: () => void; handleChange: () => void;
statsActiveUsers: number; statsActiveUsers: number;
isLicenseSetByEnvVar: boolean;
} }
export const messages = defineMessages({ export const messages = defineMessages({
@@ -52,6 +54,7 @@ const EnterpriseEditionLeftPanel = ({
fileInputRef, fileInputRef,
handleChange, handleChange,
statsActiveUsers, statsActiveUsers,
isLicenseSetByEnvVar,
}: EnterpriseEditionProps) => { }: EnterpriseEditionProps) => {
const {formatMessage} = useIntl(); const {formatMessage} = useIntl();
const [unsanitizedLicense, setUnsanitizedLicense] = useState(license); const [unsanitizedLicense, setUnsanitizedLicense] = useState(license);
@@ -148,6 +151,7 @@ const EnterpriseEditionLeftPanel = ({
handleChange, handleChange,
statsActiveUsers, statsActiveUsers,
expirationDays, expirationDays,
isLicenseSetByEnvVar,
) )
} }
</div> </div>
@@ -245,6 +249,7 @@ const renderLicenseContent = (
handleChange: () => void, handleChange: () => void,
statsActiveUsers: number, statsActiveUsers: number,
expirationDays: number, expirationDays: number,
isLicenseSetByEnvVar: boolean,
) => { ) => {
// Note: DO NOT LOCALISE THESE STRINGS. Legally we can not since the license is in English. // Note: DO NOT LOCALISE THESE STRINGS. Legally we can not since the license is in English.
@@ -284,7 +289,7 @@ const renderLicenseContent = (
<div className='licenseElements'> <div className='licenseElements'>
{licenseValues.map(renderLicenseValues(statsActiveUsers, parseInt(license.Users, 10), expirationDays))} {licenseValues.map(renderLicenseValues(statsActiveUsers, parseInt(license.Users, 10), expirationDays))}
<hr/> <hr/>
{renderAddNewLicenseButton(fileInputRef, handleChange)} {renderAddNewLicenseButton(fileInputRef, handleChange, isLicenseSetByEnvVar)}
{renderRemoveButton(handleRemove, isDisabled, removing)} {renderRemoveButton(handleRemove, isDisabled, removing)}
</div> </div>
); );
@@ -293,18 +298,28 @@ const renderLicenseContent = (
const renderAddNewLicenseButton = ( const renderAddNewLicenseButton = (
fileInputRef: RefObject<HTMLInputElement>, fileInputRef: RefObject<HTMLInputElement>,
handleChange: () => void, handleChange: () => void,
isLicenseSetByEnvVar: boolean,
) => { ) => {
return ( return (
<> <>
<button <WithTooltip
className='btn btn-tertiary add-new-licence-btn' title={defineMessage({
onClick={() => fileInputRef.current?.click()} id: 'admin.license.setByEnvVar',
defaultMessage: 'License location is set by environment variable',
})}
disabled={!isLicenseSetByEnvVar}
> >
<FormattedMessage <button
id='admin.license.keyAddNew' className={'btn btn-secondary'}
defaultMessage='Add a new license' onClick={() => fileInputRef.current?.click()}
/> disabled={isLicenseSetByEnvVar}
</button> >
<FormattedMessage
id='admin.license.keyAddNew'
defaultMessage='Add a new license'
/>
</button>
</WithTooltip>
<input <input
ref={fileInputRef} ref={fileInputRef}
type='file' type='file'

Просмотреть файл

@@ -42,6 +42,7 @@ describe('components/admin_console/license_settings/LicenseSettings', () => {
upgradedFromTE: false, upgradedFromTE: false,
enterpriseReady: true, enterpriseReady: true,
totalUsers: 10, totalUsers: 10,
environmentConfig: {},
isMySql: false, isMySql: false,
actions: { actions: {
getLicenseConfig: jest.fn(), getLicenseConfig: jest.fn(),

Просмотреть файл

@@ -5,7 +5,7 @@ import React from 'react';
import {FormattedMessage, defineMessages} from 'react-intl'; import {FormattedMessage, defineMessages} from 'react-intl';
import type {StatusOK} from '@mattermost/types/client4'; import type {StatusOK} from '@mattermost/types/client4';
import type {ClientLicense} from '@mattermost/types/config'; import type {ClientLicense, EnvironmentConfig} from '@mattermost/types/config';
import type {ServerError} from '@mattermost/types/errors'; import type {ServerError} from '@mattermost/types/errors';
import type {ServerLimits} from '@mattermost/types/limits'; import type {ServerLimits} from '@mattermost/types/limits';
import type {GetFilteredUsersStatsOpts, UsersStats} from '@mattermost/types/users'; import type {GetFilteredUsersStatsOpts, UsersStats} from '@mattermost/types/users';
@@ -45,6 +45,7 @@ type Props = {
totalUsers: number; totalUsers: number;
isDisabled: boolean; isDisabled: boolean;
prevTrialLicense: ClientLicense; prevTrialLicense: ClientLicense;
environmentConfig: Partial<EnvironmentConfig>;
isMySql: boolean; isMySql: boolean;
actions: { actions: {
getLicenseConfig: () => void; getLicenseConfig: () => void;
@@ -321,6 +322,7 @@ export default class LicenseSettings extends React.PureComponent<Props, State> {
fileInputRef={this.fileInputRef} fileInputRef={this.fileInputRef}
handleChange={this.handleChange} handleChange={this.handleChange}
statsActiveUsers={this.props.totalUsers || 0} statsActiveUsers={this.props.totalUsers || 0}
isLicenseSetByEnvVar={Boolean(this.props.environmentConfig?.ServiceSettings?.LicenseFileLocation)}
/> />
); );

Просмотреть файл

@@ -1560,6 +1560,7 @@
"admin.license.renewalCard.reviewNumbers": "Review your numbers below to ensure you renew for the right number of users.", "admin.license.renewalCard.reviewNumbers": "Review your numbers below to ensure you renew for the right number of users.",
"admin.license.renewalCard.usersNumbers_active": "Active Users: ", "admin.license.renewalCard.usersNumbers_active": "Active Users: ",
"admin.license.renewalCard.usersNumbers_licensed": "Licensed Users: ", "admin.license.renewalCard.usersNumbers_licensed": "Licensed Users: ",
"admin.license.setByEnvVar": "License location is set by environment variable",
"admin.license.title": "Edition and License", "admin.license.title": "Edition and License",
"admin.license.Trial": "Trial", "admin.license.Trial": "Trial",
"admin.license.trial-request.accept-terms": "By clicking <strong>Start trial</strong>, I agree to the <linkEvaluation>Mattermost Software and Services License Agreement</linkEvaluation>, <linkPrivacy>Privacy Policy</linkPrivacy>, and receiving product emails.", "admin.license.trial-request.accept-terms": "By clicking <strong>Start trial</strong>, I agree to the <linkEvaluation>Mattermost Software and Services License Agreement</linkEvaluation>, <linkPrivacy>Privacy Policy</linkPrivacy>, and receiving product emails.",

Просмотреть файл

@@ -269,6 +269,14 @@ button {
} }
} }
&:disabled,
&:disabled:hover,
&:disabled:active {
border-color: rgba(var(--center-channel-color-rgb), 0.32);
background: transparent;
color: rgba(var(--center-channel-color-rgb), 0.32) !important;
}
&:hover { &:hover {
background-color: rgb(var(--button-bg-rgb), 0.08); background-color: rgb(var(--button-bg-rgb), 0.08);
} }