GlobalNcd90 = 'GLOBAL_NCD_90',
GlobalNcdPage90 = 'GLOBAL_NCD_PAGE_90',
ProjectNcd90 = 'PROJECT_NCD_90',
+ ProjectNcdPage90 = 'PROJECT_NCD_PAGE_90',
BranchNcd90 = 'BRANCH_NCD_90',
}
*/
import * as React from 'react';
import { Outlet } from 'react-router-dom';
-import NCDAutoUpdateMessage from '../../components/new-code-definition/NCDAutoUpdateMessage';
import { AppState } from '../../types/appstate';
import { GlobalSettingKeys } from '../../types/settings';
import KeyboardShortcutsModal from './KeyboardShortcutsModal';
render() {
return (
<>
- <NCDAutoUpdateMessage />
<PageTracker>{this.renderPreconnectLink()}</PageTracker>
<Outlet />
<KeyboardShortcutsModal />
import A11yProvider from '../../components/a11y/A11yProvider';
import A11ySkipLinks from '../../components/a11y/A11ySkipLinks';
import SuggestionsProvider from '../../components/embed-docs-modal/SuggestionsProvider';
+import NCDAutoUpdateMessage from '../../components/new-code-definition/NCDAutoUpdateMessage';
import Workspace from '../../components/workspace/Workspace';
import GlobalFooter from './GlobalFooter';
import StartupModal from './StartupModal';
<div className="sw-sticky sw-top-0 sw-z-global-navbar">
<SystemAnnouncement />
<IndexationNotification />
+ <NCDAutoUpdateMessage />
<UpdateNotification dismissable />
<GlobalNav location={location} />
</div>
exports[`should render correctly: default 1`] = `
<Fragment>
- <withCurrentUserContext(NCDAutoUpdateMessage) />
<withRouter(withAppStateContext(PageTracker)) />
<Outlet />
<KeyboardShortcutsModal />
exports[`should render correctly: with gravatar 1`] = `
<Fragment>
- <withCurrentUserContext(NCDAutoUpdateMessage) />
<withRouter(withAppStateContext(PageTracker))>
<link
href="http://example.com"
branchList: Branch[];
component: Component;
inheritedSetting: NewCodeDefinition;
- generalSetting: NewCodeDefinition;
+ globalNewCodeDefinition: NewCodeDefinition;
}
interface State {
};
render() {
- const { branchList, inheritedSetting, generalSetting } = this.props;
+ const { branchList, inheritedSetting, globalNewCodeDefinition } = this.props;
const { branches, editedBranch, loading } = this.state;
if (branches.length < 1) {
component={this.props.component.key}
onClose={this.closeEditModal}
inheritedSetting={inheritedSetting}
- generalSetting={generalSetting}
+ globalNewCodeDefinition={globalNewCodeDefinition}
/>
)}
</>
import NewCodeDefinitionDaysOption from '../../../components/new-code-definition/NewCodeDefinitionDaysOption';
import NewCodeDefinitionPreviousVersionOption from '../../../components/new-code-definition/NewCodeDefinitionPreviousVersionOption';
import NewCodeDefinitionWarning from '../../../components/new-code-definition/NewCodeDefinitionWarning';
+import { NewCodeDefinitionLevels } from '../../../components/new-code-definition/utils';
import Spinner from '../../../components/ui/Spinner';
import { toISO8601WithOffsetString } from '../../../helpers/dates';
import { translate, translateWithParameters } from '../../../helpers/l10n';
component: string;
onClose: (branch?: string, newSetting?: NewCodeDefinition) => void;
inheritedSetting: NewCodeDefinition;
- generalSetting: NewCodeDefinition;
+ globalNewCodeDefinition: NewCodeDefinition;
}
interface State {
isChanged: boolean;
referenceBranch: string;
saving: boolean;
- selected?: NewCodeDefinitionType;
+ selectedNewCodeDefinitionType?: NewCodeDefinitionType;
}
export default class BranchNewCodeDefinitionSettingModal extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
- const { branch, branchList, inheritedSetting, generalSetting } = props;
+ const { branch, branchList, inheritedSetting, globalNewCodeDefinition } = props;
const otherBranches = branchList.filter((b) => b.name !== branch.name);
const defaultBranch = otherBranches.length > 0 ? otherBranches[0].name : '';
analysis: this.getValueFromProps(NewCodeDefinitionType.SpecificAnalysis) || '',
days:
this.getValueFromProps(NewCodeDefinitionType.NumberOfDays) ||
- getNumberOfDaysDefaultValue(generalSetting, inheritedSetting),
+ getNumberOfDaysDefaultValue(globalNewCodeDefinition, inheritedSetting),
isChanged: false,
referenceBranch:
this.getValueFromProps(NewCodeDefinitionType.ReferenceBranch) || defaultBranch,
saving: false,
- selected: branch.newCodePeriod?.type,
+ selectedNewCodeDefinitionType: branch.newCodePeriod?.type,
};
}
e.preventDefault();
const { branch, component } = this.props;
- const { analysis, analysisDate, days, referenceBranch, selected: type } = this.state;
+ const {
+ analysis,
+ analysisDate,
+ days,
+ referenceBranch,
+ selectedNewCodeDefinitionType: type,
+ } = this.state;
- const value = getSettingValue({ type, analysis, days, referenceBranch });
+ const value = getSettingValue({ type, analysis, numberOfDays: days, referenceBranch });
if (type) {
this.setState({ saving: true });
handleSelectReferenceBranch = (referenceBranch: string) =>
this.setState({ referenceBranch, isChanged: true });
- handleSelectSetting = (selected: NewCodeDefinitionType) => {
- this.setState((currentState) => ({ selected, isChanged: selected !== currentState.selected }));
+ handleSelectSetting = (selectedNewCodeDefinitionType: NewCodeDefinitionType) => {
+ this.setState((currentState) => ({
+ selectedNewCodeDefinitionType,
+ isChanged: selectedNewCodeDefinitionType !== currentState.selectedNewCodeDefinitionType,
+ }));
};
render() {
const { branch, branchList } = this.props;
- const { analysis, days, isChanged, referenceBranch, saving, selected } = this.state;
+ const { analysis, days, isChanged, referenceBranch, saving, selectedNewCodeDefinitionType } =
+ this.state;
const header = translateWithParameters('baseline.new_code_period_for_branch_x', branch.name);
const currentSettingValue = branch.newCodePeriod?.value;
const isValid = validateSetting({
- days,
+ numberOfDays: days,
referenceBranch,
- selected,
+ selectedNewCodeDefinitionType,
});
return (
newCodeDefinitionType={currentSetting}
newCodeDefinitionValue={currentSettingValue}
isBranchSupportEnabled
- level="branch"
+ level={NewCodeDefinitionLevels.Branch}
/>
<div className="display-flex-column huge-spacer-bottom sw-gap-4" role="radiogroup">
<NewCodeDefinitionPreviousVersionOption
isDefault={false}
onSelect={this.handleSelectSetting}
- selected={selected === NewCodeDefinitionType.PreviousVersion}
+ selected={selectedNewCodeDefinitionType === NewCodeDefinitionType.PreviousVersion}
/>
<NewCodeDefinitionDaysOption
days={days}
isValid={isValid}
onChangeDays={this.handleSelectDays}
onSelect={this.handleSelectSetting}
- selected={selected === NewCodeDefinitionType.NumberOfDays}
+ selected={selectedNewCodeDefinitionType === NewCodeDefinitionType.NumberOfDays}
+ settingLevel={NewCodeDefinitionLevels.Branch}
/>
<NewCodeDefinitionSettingReferenceBranch
branchList={branchList.map(this.branchToOption)}
onChangeReferenceBranch={this.handleSelectReferenceBranch}
onSelect={this.handleSelectSetting}
referenceBranch={referenceBranch}
- selected={selected === NewCodeDefinitionType.ReferenceBranch}
- settingLevel="branch"
+ selected={selectedNewCodeDefinitionType === NewCodeDefinitionType.ReferenceBranch}
+ settingLevel={NewCodeDefinitionLevels.Branch}
/>
{currentSetting === NewCodeDefinitionType.SpecificAnalysis && (
<NewCodeDefinitionSettingAnalysis
onSelect={noop}
- selected={selected === NewCodeDefinitionType.SpecificAnalysis}
+ selected={
+ selectedNewCodeDefinitionType === NewCodeDefinitionType.SpecificAnalysis
+ }
/>
)}
</div>
- {selected === NewCodeDefinitionType.SpecificAnalysis && (
+ {selectedNewCodeDefinitionType === NewCodeDefinitionType.SpecificAnalysis && (
<BranchAnalysisList
analysis={analysis}
branch={branch.name}
import Select from '../../../components/controls/Select';
import Tooltip from '../../../components/controls/Tooltip';
import AlertErrorIcon from '../../../components/icons/AlertErrorIcon';
+import { NewCodeDefinitionLevels } from '../../../components/new-code-definition/utils';
import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
import { translate, translateWithParameters } from '../../../helpers/l10n';
onSelect: (selection: NewCodeDefinitionType) => void;
referenceBranch: string;
selected: boolean;
- settingLevel: 'project' | 'branch';
+ settingLevel: Exclude<
+ NewCodeDefinitionLevels,
+ NewCodeDefinitionLevels.NewProject | NewCodeDefinitionLevels.Global
+ >;
}
export interface BranchOption {
</div>
{selected && (
<>
- {settingLevel === 'project' && (
+ {settingLevel === NewCodeDefinitionLevels.Project && (
<p className="spacer-top">{translate('baseline.reference_branch.description2')}</p>
)}
<div className="big-spacer-top display-flex-column">
interface State {
analysis?: string;
branchList: Branch[];
- currentSetting?: NewCodeDefinitionType;
- currentSettingValue?: string;
- days: string;
- generalSetting?: NewCodeDefinition;
+ newCodeDefinitionType?: NewCodeDefinitionType;
+ newCodeDefinitionValue?: string;
+ previousNonCompliantValue?: string;
+ projectNcdUpdatedAt?: number;
+ numberOfDays: string;
+ globalNewCodeDefinition?: NewCodeDefinition;
isChanged: boolean;
loading: boolean;
- overrideGeneralSetting?: boolean;
+ overrideGlobalNewCodeDefinition?: boolean;
referenceBranch?: string;
saving: boolean;
- selected?: NewCodeDefinitionType;
+ selectedNewCodeDefinitionType?: NewCodeDefinitionType;
success?: boolean;
}
mounted = false;
state: State = {
branchList: [],
- days: getNumberOfDaysDefaultValue(),
+ numberOfDays: getNumberOfDaysDefaultValue(),
isChanged: false,
loading: true,
saving: false,
}
getUpdatedState(params: {
- currentSetting?: NewCodeDefinitionType;
- currentSettingValue?: string;
- generalSetting: NewCodeDefinition;
+ newCodeDefinitionType?: NewCodeDefinitionType;
+ newCodeDefinitionValue?: string;
+ globalNewCodeDefinition: NewCodeDefinition;
+ previousNonCompliantValue?: string;
+ projectNcdUpdatedAt?: number;
}) {
- const { currentSetting, currentSettingValue, generalSetting } = params;
+ const {
+ newCodeDefinitionType,
+ newCodeDefinitionValue,
+ globalNewCodeDefinition,
+ previousNonCompliantValue,
+ projectNcdUpdatedAt,
+ } = params;
const { referenceBranch } = this.state;
- const defaultDays = getNumberOfDaysDefaultValue(generalSetting);
+ const defaultDays = getNumberOfDaysDefaultValue(globalNewCodeDefinition);
return {
loading: false,
- currentSetting,
- currentSettingValue,
- generalSetting,
+ newCodeDefinitionType,
+ newCodeDefinitionValue,
+ previousNonCompliantValue,
+ projectNcdUpdatedAt,
+ globalNewCodeDefinition,
isChanged: false,
- selected: currentSetting || generalSetting.type,
- overrideGeneralSetting: Boolean(currentSetting),
- days:
- (currentSetting === NewCodeDefinitionType.NumberOfDays && currentSettingValue) ||
+ selectedNewCodeDefinitionType: newCodeDefinitionType ?? globalNewCodeDefinition.type,
+ overrideGlobalNewCodeDefinition: Boolean(newCodeDefinitionType),
+ numberOfDays:
+ (newCodeDefinitionType === NewCodeDefinitionType.NumberOfDays && newCodeDefinitionValue) ||
defaultDays,
analysis:
- (currentSetting === NewCodeDefinitionType.SpecificAnalysis && currentSettingValue) || '',
+ (newCodeDefinitionType === NewCodeDefinitionType.SpecificAnalysis &&
+ newCodeDefinitionValue) ||
+ '',
referenceBranch:
- (currentSetting === NewCodeDefinitionType.ReferenceBranch && currentSettingValue) ||
+ (newCodeDefinitionType === NewCodeDefinitionType.ReferenceBranch &&
+ newCodeDefinitionValue) ||
referenceBranch,
};
}
project: component.key,
}),
]).then(
- ([generalSetting, setting]) => {
+ ([globalNewCodeDefinition, setting]) => {
if (this.mounted) {
- if (!generalSetting.type) {
- generalSetting = { type: DEFAULT_NEW_CODE_DEFINITION_TYPE };
+ if (!globalNewCodeDefinition.type) {
+ globalNewCodeDefinition = { type: DEFAULT_NEW_CODE_DEFINITION_TYPE };
}
- const currentSettingValue = setting.value;
- const currentSetting = setting.inherited
+ const newCodeDefinitionValue = setting.value;
+ const newCodeDefinitionType = setting.inherited
? undefined
: setting.type || DEFAULT_NEW_CODE_DEFINITION_TYPE;
this.setState(
this.getUpdatedState({
- generalSetting,
- currentSetting,
- currentSettingValue,
+ globalNewCodeDefinition,
+ newCodeDefinitionType,
+ newCodeDefinitionValue,
+ previousNonCompliantValue: setting.previousNonCompliantValue,
+ projectNcdUpdatedAt: setting.updatedAt,
})
);
}
() => {
this.setState({
saving: false,
- currentSetting: undefined,
+ newCodeDefinitionType: undefined,
isChanged: false,
- selected: undefined,
+ selectedNewCodeDefinitionType: undefined,
success: true,
});
this.resetSuccess();
);
};
- handleSelectDays = (days: string) => this.setState({ days, isChanged: true });
+ handleSelectDays = (days: string) => this.setState({ numberOfDays: days, isChanged: true });
handleSelectReferenceBranch = (referenceBranch: string) => {
this.setState({ referenceBranch, isChanged: true });
handleCancel = () =>
this.setState(
({
- generalSetting = { type: DEFAULT_NEW_CODE_DEFINITION_TYPE },
- currentSetting,
- currentSettingValue,
- }) => this.getUpdatedState({ generalSetting, currentSetting, currentSettingValue })
+ globalNewCodeDefinition = { type: DEFAULT_NEW_CODE_DEFINITION_TYPE },
+ newCodeDefinitionType,
+ newCodeDefinitionValue,
+ }) =>
+ this.getUpdatedState({
+ globalNewCodeDefinition,
+ newCodeDefinitionType,
+ newCodeDefinitionValue,
+ })
);
- handleSelectSetting = (selected?: NewCodeDefinitionType) => {
+ handleSelectSetting = (selectedNewCodeDefinitionType?: NewCodeDefinitionType) => {
this.setState((currentState) => ({
- selected,
- isChanged: selected !== currentState.selected,
+ selectedNewCodeDefinitionType,
+ isChanged: selectedNewCodeDefinitionType !== currentState.selectedNewCodeDefinitionType,
}));
};
- handleToggleSpecificSetting = (overrideGeneralSetting: boolean) =>
+ handleToggleSpecificSetting = (overrideGlobalNewCodeDefinition: boolean) =>
this.setState((currentState) => ({
- overrideGeneralSetting,
- isChanged: currentState.overrideGeneralSetting !== overrideGeneralSetting,
+ overrideGlobalNewCodeDefinition,
+ isChanged: currentState.overrideGlobalNewCodeDefinition !== overrideGlobalNewCodeDefinition,
}));
handleSubmit = (e: React.SyntheticEvent<HTMLFormElement>) => {
e.preventDefault();
const { component } = this.props;
- const { days, selected: type, referenceBranch, overrideGeneralSetting } = this.state;
+ const {
+ numberOfDays,
+ selectedNewCodeDefinitionType: type,
+ referenceBranch,
+ overrideGlobalNewCodeDefinition,
+ } = this.state;
- if (!overrideGeneralSetting) {
+ if (!overrideGlobalNewCodeDefinition) {
this.resetSetting();
return;
}
- const value = getSettingValue({ type, days, referenceBranch });
+ const value = getSettingValue({ type, numberOfDays, referenceBranch });
if (type) {
this.setState({ saving: true });
() => {
this.setState({
saving: false,
- currentSetting: type,
- currentSettingValue: value || undefined,
+ newCodeDefinitionType: type,
+ newCodeDefinitionValue: value || undefined,
+ previousNonCompliantValue: undefined,
+ projectNcdUpdatedAt: Date.now(),
isChanged: false,
success: true,
});
const {
analysis,
branchList,
- currentSetting,
- days,
- generalSetting,
+ newCodeDefinitionType,
+ numberOfDays,
+ previousNonCompliantValue,
+ projectNcdUpdatedAt,
+ globalNewCodeDefinition,
isChanged,
loading,
- currentSettingValue,
- overrideGeneralSetting,
+ newCodeDefinitionValue,
+ overrideGlobalNewCodeDefinition,
referenceBranch,
saving,
- selected,
+ selectedNewCodeDefinitionType,
success,
} = this.state;
const branchSupportEnabled = this.props.hasFeature(Feature.BranchSupport);
<div className="panel-white project-baseline">
{branchSupportEnabled && <h2>{translate('project_baseline.default_setting')}</h2>}
- {generalSetting && overrideGeneralSetting !== undefined && (
+ {globalNewCodeDefinition && overrideGlobalNewCodeDefinition !== undefined && (
<ProjectNewCodeDefinitionSelector
analysis={analysis}
branch={branchLike}
branchesEnabled={branchSupportEnabled}
canAdmin={appState.canAdmin}
component={component.key}
- currentSetting={currentSetting}
- currentSettingValue={currentSettingValue}
- days={days}
- generalSetting={generalSetting}
+ newCodeDefinitionType={newCodeDefinitionType}
+ newCodeDefinitionValue={newCodeDefinitionValue}
+ days={numberOfDays}
+ previousNonCompliantValue={previousNonCompliantValue}
+ projectNcdUpdatedAt={projectNcdUpdatedAt}
+ globalNewCodeDefinition={globalNewCodeDefinition}
isChanged={isChanged}
onCancel={this.handleCancel}
onSelectDays={this.handleSelectDays}
onSelectSetting={this.handleSelectSetting}
onSubmit={this.handleSubmit}
onToggleSpecificSetting={this.handleToggleSpecificSetting}
- overrideGeneralSetting={overrideGeneralSetting}
+ overrideGlobalNewCodeDefinition={overrideGlobalNewCodeDefinition}
referenceBranch={referenceBranch}
saving={saving}
- selected={selected}
+ selectedNewCodeDefinitionType={selectedNewCodeDefinitionType}
/>
)}
{translate('settings.state.saved')}
</span>
</div>
- {generalSetting && branchSupportEnabled && (
+ {globalNewCodeDefinition && branchSupportEnabled && (
<div className="huge-spacer-top branch-baseline-selector">
<hr />
<h2>{translate('project_baseline.configure_branches')}</h2>
branchList={branchList}
component={component}
inheritedSetting={
- currentSetting
+ newCodeDefinitionType
? {
- type: currentSetting,
- value: currentSettingValue,
+ type: newCodeDefinitionType,
+ value: newCodeDefinitionValue,
}
- : generalSetting
+ : globalNewCodeDefinition
}
- generalSetting={generalSetting}
+ globalNewCodeDefinition={globalNewCodeDefinition}
/>
</div>
)}
import NewCodeDefinitionDaysOption from '../../../components/new-code-definition/NewCodeDefinitionDaysOption';
import NewCodeDefinitionPreviousVersionOption from '../../../components/new-code-definition/NewCodeDefinitionPreviousVersionOption';
import NewCodeDefinitionWarning from '../../../components/new-code-definition/NewCodeDefinitionWarning';
+import { NewCodeDefinitionLevels } from '../../../components/new-code-definition/utils';
import { Alert } from '../../../components/ui/Alert';
import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
branchesEnabled?: boolean;
canAdmin: boolean | undefined;
component: string;
- currentSetting?: NewCodeDefinitionType;
- currentSettingValue?: string;
+ newCodeDefinitionType?: NewCodeDefinitionType;
+ newCodeDefinitionValue?: string;
+ previousNonCompliantValue?: string;
+ projectNcdUpdatedAt?: number;
days: string;
- generalSetting: NewCodeDefinition;
+ globalNewCodeDefinition: NewCodeDefinition;
isChanged: boolean;
onCancel: () => void;
onSelectDays: (value: string) => void;
onToggleSpecificSetting: (selection: boolean) => void;
referenceBranch?: string;
saving: boolean;
- selected?: NewCodeDefinitionType;
- overrideGeneralSetting: boolean;
+ selectedNewCodeDefinitionType?: NewCodeDefinitionType;
+ overrideGlobalNewCodeDefinition: boolean;
}
function branchToOption(b: Branch) {
branchesEnabled,
canAdmin,
component,
- currentSetting,
- currentSettingValue,
+ newCodeDefinitionType,
+ newCodeDefinitionValue,
+ previousNonCompliantValue,
+ projectNcdUpdatedAt,
days,
- generalSetting,
+ globalNewCodeDefinition,
isChanged,
- overrideGeneralSetting,
+ overrideGlobalNewCodeDefinition,
referenceBranch,
saving,
- selected,
+ selectedNewCodeDefinitionType,
} = props;
- const isGlobalNcdCompliant = isNewCodeDefinitionCompliant(generalSetting);
+ const isGlobalNcdCompliant = isNewCodeDefinitionCompliant(globalNewCodeDefinition);
const isValid = validateSetting({
- days,
- overrideGeneralSetting,
+ numberOfDays: days,
+ overrideGlobalNewCodeDefinition,
referenceBranch,
- selected,
+ selectedNewCodeDefinitionType,
});
if (branch === undefined) {
<form className="project-baseline-selector" onSubmit={props.onSubmit}>
<div className="big-spacer-top spacer-bottom" role="radiogroup">
<RadioButton
- checked={!overrideGeneralSetting}
+ checked={!overrideGlobalNewCodeDefinition}
className="big-spacer-bottom"
disabled={!isGlobalNcdCompliant}
onCheck={() => props.onToggleSpecificSetting(false)}
<div className="sw-ml-4">
<GlobalNewCodeDefinitionDescription
- globalNcd={generalSetting}
+ globalNcd={globalNewCodeDefinition}
isGlobalNcdCompliant={isGlobalNcdCompliant}
canAdmin={canAdmin}
/>
</div>
<RadioButton
- checked={overrideGeneralSetting}
+ checked={overrideGlobalNewCodeDefinition}
className="huge-spacer-top"
onCheck={() => props.onToggleSpecificSetting(true)}
value="specific"
<div className="big-spacer-left big-spacer-right project-baseline-setting">
<NewCodeDefinitionWarning
- newCodeDefinitionType={currentSetting}
- newCodeDefinitionValue={currentSettingValue}
+ newCodeDefinitionType={newCodeDefinitionType}
+ newCodeDefinitionValue={newCodeDefinitionValue}
isBranchSupportEnabled={branchesEnabled}
- level="project"
+ level={NewCodeDefinitionLevels.Project}
/>
<div className="display-flex-column big-spacer-bottom sw-gap-4" role="radiogroup">
<NewCodeDefinitionPreviousVersionOption
- disabled={!overrideGeneralSetting}
+ disabled={!overrideGlobalNewCodeDefinition}
onSelect={props.onSelectSetting}
- selected={overrideGeneralSetting && selected === NewCodeDefinitionType.PreviousVersion}
+ selected={
+ overrideGlobalNewCodeDefinition &&
+ selectedNewCodeDefinitionType === NewCodeDefinitionType.PreviousVersion
+ }
/>
<NewCodeDefinitionDaysOption
days={days}
- disabled={!overrideGeneralSetting}
+ currentDaysValue={
+ newCodeDefinitionType === NewCodeDefinitionType.NumberOfDays
+ ? newCodeDefinitionValue
+ : undefined
+ }
+ previousNonCompliantValue={previousNonCompliantValue}
+ updatedAt={projectNcdUpdatedAt}
+ disabled={!overrideGlobalNewCodeDefinition}
isChanged={isChanged}
isValid={isValid}
onChangeDays={props.onSelectDays}
onSelect={props.onSelectSetting}
- selected={overrideGeneralSetting && selected === NewCodeDefinitionType.NumberOfDays}
+ selected={
+ overrideGlobalNewCodeDefinition &&
+ selectedNewCodeDefinitionType === NewCodeDefinitionType.NumberOfDays
+ }
+ settingLevel={NewCodeDefinitionLevels.Project}
/>
{branchesEnabled && (
<NewCodeDefinitionSettingReferenceBranch
branchList={branchList.map(branchToOption)}
- disabled={!overrideGeneralSetting}
+ disabled={!overrideGlobalNewCodeDefinition}
onChangeReferenceBranch={props.onSelectReferenceBranch}
onSelect={props.onSelectSetting}
referenceBranch={referenceBranch || ''}
selected={
- overrideGeneralSetting && selected === NewCodeDefinitionType.ReferenceBranch
+ overrideGlobalNewCodeDefinition &&
+ selectedNewCodeDefinitionType === NewCodeDefinitionType.ReferenceBranch
}
- settingLevel="project"
+ settingLevel={NewCodeDefinitionLevels.Project}
/>
)}
- {!branchesEnabled && currentSetting === NewCodeDefinitionType.SpecificAnalysis && (
+ {!branchesEnabled && newCodeDefinitionType === NewCodeDefinitionType.SpecificAnalysis && (
<NewCodeDefinitionSettingAnalysis
onSelect={noop}
selected={
- overrideGeneralSetting && selected === NewCodeDefinitionType.SpecificAnalysis
+ overrideGlobalNewCodeDefinition &&
+ selectedNewCodeDefinitionType === NewCodeDefinitionType.SpecificAnalysis
}
/>
)}
</div>
{!branchesEnabled &&
- overrideGeneralSetting &&
- selected === NewCodeDefinitionType.SpecificAnalysis && (
+ overrideGlobalNewCodeDefinition &&
+ selectedNewCodeDefinitionType === NewCodeDefinitionType.SpecificAnalysis && (
<BranchAnalysisList
analysis={analysis || ''}
branch={branch.name}
describe('getSettingValue', () => {
const state = {
analysis: 'analysis',
- days: '35',
+ numberOfDays: '35',
referenceBranch: 'branch-4.2',
};
it('should work for Days', () => {
expect(getSettingValue({ ...state, type: NewCodeDefinitionType.NumberOfDays })).toBe(
- state.days
+ state.numberOfDays
);
});
describe('validateSettings', () => {
it('should validate at branch level', () => {
- expect(validateSetting({ days: '' })).toEqual(false);
+ expect(validateSetting({ numberOfDays: '' })).toEqual(false);
expect(
validateSetting({
- days: '12',
- selected: NewCodeDefinitionType.NumberOfDays,
+ numberOfDays: '12',
+ selectedNewCodeDefinitionType: NewCodeDefinitionType.NumberOfDays,
})
).toEqual(true);
expect(
validateSetting({
- days: 'nope',
- selected: NewCodeDefinitionType.NumberOfDays,
+ numberOfDays: 'nope',
+ selectedNewCodeDefinitionType: NewCodeDefinitionType.NumberOfDays,
})
).toEqual(false);
expect(
validateSetting({
- days: '',
- selected: NewCodeDefinitionType.SpecificAnalysis,
+ numberOfDays: '',
+ selectedNewCodeDefinitionType: NewCodeDefinitionType.SpecificAnalysis,
})
).toEqual(false);
expect(
validateSetting({
- days: '',
+ numberOfDays: '',
referenceBranch: 'master',
- selected: NewCodeDefinitionType.ReferenceBranch,
+ selectedNewCodeDefinitionType: NewCodeDefinitionType.ReferenceBranch,
})
).toEqual(true);
expect(
validateSetting({
- days: '',
+ numberOfDays: '',
referenceBranch: '',
- selected: NewCodeDefinitionType.ReferenceBranch,
+ selectedNewCodeDefinitionType: NewCodeDefinitionType.ReferenceBranch,
})
).toEqual(false);
});
it('should validate at project level', () => {
- expect(validateSetting({ days: '', overrideGeneralSetting: false })).toEqual(true);
+ expect(validateSetting({ numberOfDays: '', overrideGlobalNewCodeDefinition: false })).toEqual(
+ true
+ );
expect(
validateSetting({
- selected: NewCodeDefinitionType.PreviousVersion,
- days: '',
- overrideGeneralSetting: true,
+ selectedNewCodeDefinitionType: NewCodeDefinitionType.PreviousVersion,
+ numberOfDays: '',
+ overrideGlobalNewCodeDefinition: true,
})
).toEqual(true);
expect(
validateSetting({
- selected: NewCodeDefinitionType.NumberOfDays,
- days: '',
- overrideGeneralSetting: true,
+ selectedNewCodeDefinitionType: NewCodeDefinitionType.NumberOfDays,
+ numberOfDays: '',
+ overrideGlobalNewCodeDefinition: true,
})
).toEqual(false);
expect(
validateSetting({
- selected: NewCodeDefinitionType.NumberOfDays,
- days: '12',
- overrideGeneralSetting: true,
+ selectedNewCodeDefinitionType: NewCodeDefinitionType.NumberOfDays,
+ numberOfDays: '12',
+ overrideGlobalNewCodeDefinition: true,
})
).toEqual(true);
});
export function getSettingValue({
analysis,
- days,
+ numberOfDays,
referenceBranch,
type,
}: {
analysis?: string;
- days?: string;
+ numberOfDays?: string;
referenceBranch?: string;
type?: NewCodeDefinitionType;
}) {
switch (type) {
case NewCodeDefinitionType.NumberOfDays:
- return days;
+ return numberOfDays;
case NewCodeDefinitionType.ReferenceBranch:
return referenceBranch;
case NewCodeDefinitionType.SpecificAnalysis:
}
export function validateSetting(state: {
- days: string;
- overrideGeneralSetting?: boolean;
+ numberOfDays: string;
+ overrideGlobalNewCodeDefinition?: boolean;
referenceBranch?: string;
- selected?: NewCodeDefinitionType;
+ selectedNewCodeDefinitionType?: NewCodeDefinitionType;
}) {
- const { days, overrideGeneralSetting, referenceBranch = '', selected } = state;
+ const {
+ numberOfDays,
+ overrideGlobalNewCodeDefinition,
+ referenceBranch = '',
+ selectedNewCodeDefinitionType,
+ } = state;
return (
- overrideGeneralSetting === false ||
- (!!selected &&
+ overrideGlobalNewCodeDefinition === false ||
+ (!!selectedNewCodeDefinitionType &&
isNewCodeDefinitionCompliant({
- type: selected,
- value: days,
+ type: selectedNewCodeDefinitionType,
+ value: numberOfDays,
}) &&
- (selected !== NewCodeDefinitionType.ReferenceBranch || referenceBranch.length > 0))
+ (selectedNewCodeDefinitionType !== NewCodeDefinitionType.ReferenceBranch ||
+ referenceBranch.length > 0))
);
}
import NewCodeDefinitionDaysOption from '../../../components/new-code-definition/NewCodeDefinitionDaysOption';
import NewCodeDefinitionPreviousVersionOption from '../../../components/new-code-definition/NewCodeDefinitionPreviousVersionOption';
import NewCodeDefinitionWarning from '../../../components/new-code-definition/NewCodeDefinitionWarning';
+import { NewCodeDefinitionLevels } from '../../../components/new-code-definition/utils';
import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import {
loading: boolean;
currentSettingValue?: string;
isChanged: boolean;
+ projectKey?: string;
saving: boolean;
selected?: NewCodeDefinitionType;
success: boolean;
fetchNewCodePeriodSetting() {
getNewCodeDefinition()
- .then(({ type, value, previousNonCompliantValue, updatedAt }) => {
+ .then(({ type, value, previousNonCompliantValue, projectKey, updatedAt }) => {
this.setState(({ days }) => ({
currentSetting: type,
days: type === NewCodeDefinitionType.NumberOfDays ? String(value) : days,
currentSettingValue: value,
selected: type,
previousNonCompliantValue,
+ projectKey,
ncdUpdatedAt: updatedAt,
}));
})
saving: false,
currentSetting: type,
currentSettingValue: value || undefined,
+ previousNonCompliantValue: undefined,
+ ncdUpdatedAt: Date.now(),
isChanged: false,
success: true,
});
loading,
isChanged,
currentSettingValue,
+ projectKey,
saving,
selected,
success,
<NewCodeDefinitionDaysOption
className="spacer-top sw-mb-4"
days={days}
+ currentDaysValue={
+ currentSetting === NewCodeDefinitionType.NumberOfDays
+ ? currentSettingValue
+ : undefined
+ }
previousNonCompliantValue={previousNonCompliantValue}
+ projectKey={projectKey}
updatedAt={ncdUpdatedAt}
isChanged={isChanged}
isValid={isValid}
onChangeDays={this.onSelectDays}
onSelect={this.onSelectSetting}
selected={selected === NewCodeDefinitionType.NumberOfDays}
+ settingLevel={NewCodeDefinitionLevels.Global}
/>
<NewCodeDefinitionWarning
newCodeDefinitionType={currentSetting}
newCodeDefinitionValue={currentSettingValue}
isBranchSupportEnabled={undefined}
- level="global"
+ level={NewCodeDefinitionLevels.Global}
/>
{isChanged && (
<div className="big-spacer-top">
daysInput: byRole('spinbutton') /* spinbutton is the default role for a number input */,
saveButton: byRole('button', { name: 'save' }),
cancelButton: byRole('button', { name: 'cancel' }),
- ncdAutoUpdateMessage: byText(/new_code_definition.auto_update.global.page.message/),
+ ncdAutoUpdateMessage: byText(/new_code_definition.auto_update.ncd_page.message/),
ncdAutoUpdateMessageDismiss: byLabelText('alert.dismiss'),
};
: 'new_code_definition.auto_update.project.message';
return (
- <DismissableAlertComponent onDismiss={handleBannerDismiss} variant="info" display="banner">
+ <DismissableAlertComponent
+ onDismiss={handleBannerDismiss}
+ variant="info"
+ display="banner"
+ bannerClassName="sw-mb-0"
+ >
<FormattedMessage
id={bannerMessageId}
values={{
import { FlagErrorIcon, InputField, Note, SelectionCard } from 'design-system';
import { noop } from 'lodash';
import * as React from 'react';
-import { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
import { FormattedMessage } from 'react-intl';
-import { checkMessageDismissed, MessageTypes, setMessageDismissed } from '../../api/messages';
+import { MessageTypes, checkMessageDismissed, setMessageDismissed } from '../../api/messages';
import { translate, translateWithParameters } from '../../helpers/l10n';
import {
NUMBER_OF_DAYS_MAX_VALUE,
import { NewCodeDefinitionType } from '../../types/new-code-definition';
import DocLink from '../common/DocLink';
import DismissableAlertComponent from '../ui/DismissableAlertComponent';
+import { NewCodeDefinitionLevels } from './utils';
export interface Props {
className?: string;
days: string;
+ currentDaysValue?: string;
previousNonCompliantValue?: string;
+ projectKey?: string;
updatedAt?: number;
disabled?: boolean;
isChanged: boolean;
onChangeDays: (value: string) => void;
onSelect: (selection: NewCodeDefinitionType) => void;
selected: boolean;
+ settingLevel: NewCodeDefinitionLevels;
}
export default function NewCodeDefinitionDaysOption(props: Props) {
const {
className,
days,
+ currentDaysValue,
previousNonCompliantValue,
+ projectKey,
updatedAt,
disabled,
isChanged,
onChangeDays,
onSelect,
selected,
+ settingLevel,
} = props;
const [ncdAutoUpdateBannerDismissed, setNcdAutoUpdateBannerDismissed] = useState(true);
useEffect(() => {
async function fetchMessageDismissed() {
- const messageStatus = await checkMessageDismissed({
- messageType: MessageTypes.GlobalNcdPage90,
- });
+ const messageStatus = await checkMessageDismissed(
+ projectKey
+ ? {
+ messageType: MessageTypes.ProjectNcdPage90,
+ projectKey,
+ }
+ : {
+ messageType: MessageTypes.GlobalNcdPage90,
+ }
+ );
setNcdAutoUpdateBannerDismissed(messageStatus.dismissed);
}
if (isDefined(previousNonCompliantValue)) {
fetchMessageDismissed().catch(noop);
}
- }, [previousNonCompliantValue]);
+ }, [previousNonCompliantValue, projectKey, settingLevel]);
+
+ const shouldShowAutoUpdateBanner = useMemo(() => {
+ return (
+ (settingLevel === NewCodeDefinitionLevels.Global ||
+ settingLevel === NewCodeDefinitionLevels.Project) &&
+ isDefined(previousNonCompliantValue) &&
+ isDefined(updatedAt) &&
+ !disabled &&
+ !ncdAutoUpdateBannerDismissed
+ );
+ }, [disabled, ncdAutoUpdateBannerDismissed, previousNonCompliantValue, settingLevel, updatedAt]);
const handleBannerDismiss = useCallback(async () => {
await setMessageDismissed({ messageType: MessageTypes.GlobalNcdPage90 });
)}
</Note>
- {isDefined(previousNonCompliantValue) &&
- isDefined(updatedAt) &&
- !ncdAutoUpdateBannerDismissed && (
- <DismissableAlertComponent
- variant="info"
- display="inline"
- className="sw-mt-4 sw-max-w-[800px]"
- onDismiss={handleBannerDismiss}
- >
- <FormattedMessage
- defaultMessage="new_code_definition.auto_update.global.page.message"
- id="new_code_definition.auto_update.global.page.message"
- tagName="span"
- values={{
- previousDays: previousNonCompliantValue,
- days,
- date: new Date(updatedAt).toLocaleDateString(),
- link: (
- <DocLink to="/project-administration/clean-as-you-code-settings/defining-new-code/#new-code-definition-options">
- {translate('learn_more')}
- </DocLink>
- ),
- }}
- />
- </DismissableAlertComponent>
- )}
+ {shouldShowAutoUpdateBanner && (
+ <DismissableAlertComponent
+ variant="info"
+ display="inline"
+ className="sw-mt-4 sw-max-w-[800px]"
+ onDismiss={handleBannerDismiss}
+ >
+ <FormattedMessage
+ defaultMessage="new_code_definition.auto_update.ncd_page.message"
+ id="new_code_definition.auto_update.ncd_page.message"
+ tagName="span"
+ values={{
+ previousDays: previousNonCompliantValue,
+ days: currentDaysValue,
+ date: isDefined(updatedAt) && new Date(updatedAt).toLocaleDateString(),
+ link: (
+ <DocLink to="/project-administration/clean-as-you-code-settings/defining-new-code/#new-code-definition-options">
+ {translate('learn_more')}
+ </DocLink>
+ ),
+ }}
+ />
+ </DismissableAlertComponent>
+ )}
</div>
)}
</>
import GlobalNewCodeDefinitionDescription from './GlobalNewCodeDefinitionDescription';
import NewCodeDefinitionDaysOption from './NewCodeDefinitionDaysOption';
import NewCodeDefinitionPreviousVersionOption from './NewCodeDefinitionPreviousVersionOption';
+import { NewCodeDefinitionLevels } from './utils';
interface Props {
canAdmin: boolean | undefined;
onChangeDays={setDays}
onSelect={handleNcdChanged}
selected={selectedNcdType === NewCodeDefinitionType.NumberOfDays}
+ settingLevel={NewCodeDefinitionLevels.NewProject}
/>
<SelectionCard
import { NewCodeDefinitionType } from '../../types/new-code-definition';
import DocLink from '../common/DocLink';
import { Alert } from '../ui/Alert';
+import { NewCodeDefinitionLevels } from './utils';
export interface NewCodeDefinitionWarningProps {
newCodeDefinitionType: NewCodeDefinitionType | undefined;
newCodeDefinitionValue: string | undefined;
isBranchSupportEnabled: boolean | undefined;
- level: 'branch' | 'project' | 'global';
+ level: Exclude<NewCodeDefinitionLevels, NewCodeDefinitionLevels.NewProject>;
}
export default function NewCodeDefinitionWarning({
<p className="sw-mb-2">
{translate(
`baseline.number_days.compliance_warning.content.${level}${
- isBranchSupportEnabled && level === 'project' ? '.with_branch_support' : ''
+ isBranchSupportEnabled && level === NewCodeDefinitionLevels.Project
+ ? '.with_branch_support'
+ : ''
}`
)}
</p>
import { Component } from '../../types/types';
import { CurrentUser, isLoggedIn } from '../../types/users';
+export enum NewCodeDefinitionLevels {
+ Global = 'GLOBAL',
+ Project = 'PROJECT',
+ Branch = 'BRANCH',
+ NewProject = 'NEW_PROJECT',
+}
+
export type PreviouslyNonCompliantNCD = NewCodeDefinition &
Required<Pick<NewCodeDefinition, 'previousNonCompliantValue' | 'updatedAt'>>;
import { Alert, AlertProps } from './Alert';
export interface DismissableAlertComponentProps extends AlertProps {
+ bannerClassName?: string;
className?: string;
children: React.ReactNode;
onDismiss: () => void;
}
export default function DismissableAlertComponent(props: DismissableAlertComponentProps) {
- const { className, display = 'banner', variant, children, onDismiss } = props;
+ const { bannerClassName, className, display = 'banner', variant, children, onDismiss } = props;
return (
<div className={classNames('dismissable-alert-wrapper', className)}>
- <Alert className={`dismissable-alert-${display}`} display={display} variant={variant}>
+ <Alert
+ className={classNames(`dismissable-alert-${display}`, bannerClassName)}
+ display={display}
+ variant={variant}
+ >
<div className="display-flex-center dismissable-alert-content">
<div className="flex-1">{children}</div>
<ButtonIcon aria-label={translate('alert.dismiss')} onClick={onDismiss}>
new_code_definition.reference_branch.notice=The main branch will be set as the reference branch when the project is created. You will be able to choose another branch as the reference branch when your project will have more branches.
new_code_definition.auto_update.global.message=The global new code definition was automatically changed from {previousDays} to {days} days on {date}, following a SonarQube upgrade, as it was exceeding the maximum value. {link}
-new_code_definition.auto_update.global.page.message=The number of days was automatically changed from {previousDays} to {days} on {date}, following a SonarQube upgrade, as it was exceeding the maximum value. {link}
+new_code_definition.auto_update.ncd_page.message=The number of days was automatically changed from {previousDays} to {days} on {date}, following a SonarQube upgrade, as it was exceeding the maximum value. {link}
new_code_definition.auto_update.project.message=This project's new code definition was automatically changed from {previousDays} to {days} days on {date}, following a SonarQube upgrade, as it was exceeding the maximum value. {link}
new_code_definition.auto_update.review_link=Review new code definition