size?: Size;
}
-export function GenericAvatar({ className, Icon, name, size = 'sm' }: GenericAvatarProps) {
+export function GenericAvatar({
+ className,
+ Icon,
+ name,
+ size = 'sm',
+}: Readonly<GenericAvatarProps>) {
const theme = useTheme();
const text = name.length > 0 ? name[0].toUpperCase() : '';
LAYOUT_FOOTER_HEIGHT,
LAYOUT_GLOBAL_NAV_HEIGHT,
LargeCenteredLayout,
+ PageContentFontWrapper,
+ Spinner,
themeBorder,
themeColor,
} from 'design-system';
import { fetchQualityGates } from '../../../api/quality-gates';
import Suggestions from '../../../components/embed-docs-modal/Suggestions';
import '../../../components/search-navigator.css';
-import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import {
addSideBarClass,
return (
<LargeCenteredLayout id="quality-gates-page">
- <Helmet
- defer={false}
- titleTemplate={translateWithParameters(
- 'page_title.template.with_category',
- translate('quality_gates.page'),
- )}
- />
- <div className="sw-grid sw-gap-x-12 sw-gap-y-6 sw-grid-cols-12 sw-w-full">
- <Suggestions suggestions="quality_gates" />
-
- <StyledContentWrapper
- className="sw-col-span-3 sw-px-4 sw-py-6 sw-border-t-0 sw-rounded-0"
- style={{
- height: `calc(100vh - ${LAYOUT_GLOBAL_NAV_HEIGHT + LAYOUT_FOOTER_HEIGHT}px)`,
- }}
- >
- <ListHeader canCreate={canCreate} refreshQualityGates={this.fetchQualityGates} />
- <Spinner loading={this.state.loading}>
- <List qualityGates={qualityGates} currentQualityGate={name} />
- </Spinner>
- </StyledContentWrapper>
-
- {name !== undefined && (
+ <PageContentFontWrapper className="sw-body-sm">
+ <Helmet
+ defer={false}
+ titleTemplate={translateWithParameters(
+ 'page_title.template.with_category',
+ translate('quality_gates.page'),
+ )}
+ />
+ <div className="sw-grid sw-gap-x-12 sw-gap-y-6 sw-grid-cols-12 sw-w-full">
+ <Suggestions suggestions="quality_gates" />
+
<StyledContentWrapper
- className="sw-col-span-9 sw-overflow-y-auto sw-mt-12"
+ className="sw-col-span-3 sw-px-4 sw-py-6 sw-border-t-0 sw-rounded-0"
style={{
- height: `calc(100vh - ${
- LAYOUT_GLOBAL_NAV_HEIGHT + LAYOUT_FOOTER_HEIGHT
- }px - ${MAIN_CONTENT_TOP_PADDING}px)`,
+ height: `calc(100vh - ${LAYOUT_GLOBAL_NAV_HEIGHT + LAYOUT_FOOTER_HEIGHT}px)`,
}}
>
- <Details
- qualityGateName={name}
- onSetDefault={this.handleSetDefault}
- qualityGates={this.state.qualityGates}
- refreshQualityGates={this.fetchQualityGates}
- />
+ <ListHeader canCreate={canCreate} refreshQualityGates={this.fetchQualityGates} />
+ <Spinner loading={this.state.loading}>
+ <List qualityGates={qualityGates} currentQualityGate={name} />
+ </Spinner>
</StyledContentWrapper>
- )}
- </div>
+
+ {name !== undefined && (
+ <StyledContentWrapper
+ className="sw-col-span-9 sw-overflow-y-auto sw-mt-12"
+ style={{
+ height: `calc(100vh - ${
+ LAYOUT_GLOBAL_NAV_HEIGHT + LAYOUT_FOOTER_HEIGHT
+ }px - ${MAIN_CONTENT_TOP_PADDING}px)`,
+ }}
+ >
+ <Details
+ qualityGateName={name}
+ onSetDefault={this.handleSetDefault}
+ qualityGates={this.state.qualityGates}
+ refreshQualityGates={this.fetchQualityGates}
+ />
+ </StyledContentWrapper>
+ )}
+ </div>
+ </PageContentFontWrapper>
</LargeCenteredLayout>
);
}
import * as React from 'react';
import { translate } from '../../../helpers/l10n';
-export default function CaycConditionsListItem({ index, last }: { index: number; last: boolean }) {
+export default function CaycConditionsListItem({
+ index,
+ last,
+}: Readonly<{ index: number; last: boolean }>) {
return (
<li className={classNames('sw-flex', { 'sw-mb-2': !last })}>
<CheckIcon className="sw-mr-1 sw-pt-1/2" />
qualityGate: QualityGate;
}
-export default function CaycReviewUpdateConditionsModal(props: Props) {
+export default function CaycReviewUpdateConditionsModal(props: Readonly<Props>) {
const {
conditions,
qualityGate,
const { weakConditions, missingConditions } = getWeakMissingAndNonCaycConditions(conditions);
const sortedWeakConditions = sortBy(
weakConditions,
- (condition) => metrics[condition.metric] && metrics[condition.metric].name,
+ (condition) => metrics[condition.metric]?.name,
);
const sortedMissingConditions = sortBy(
missingConditions,
- (condition) => metrics[condition.metric] && metrics[condition.metric].name,
+ (condition) => metrics[condition.metric]?.name,
);
const getDocUrl = useDocUrl();
appState: { settings },
metric,
isToBeModified = false,
-}: Props) {
+}: Readonly<Props>) {
if (condition.metric === MetricKey.new_maintainability_rating) {
const maintainabilityGrid = getMaintainabilityGrid(
settings[GlobalSettingKeys.RatingGrid] ?? '',
const [editing, setEditing] = React.useState<boolean>(
qualityGate.caycStatus === CaycStatus.NonCompliant,
);
+ const { name } = qualityGate;
const canEdit = Boolean(qualityGate.actions?.manageConditions);
const { conditions = [] } = qualityGate;
const existingConditions = conditions.filter((condition) => metrics[condition.metric]);
const getDocUrl = useDocUrl();
+ // set edit only when the name is change
+ // i.e when user changes the quality gate
React.useEffect(() => {
setEditing(qualityGate.caycStatus === CaycStatus.NonCompliant);
- }, [qualityGate]);
+ }, [name]); // eslint-disable-line react-hooks/exhaustive-deps
const renderConditionModal = React.useCallback(
({ onClose }: ModalProps) => {
)}
{qualityGate.caycStatus !== CaycStatus.NonCompliant && !editing && canEdit && (
- <div className="sw-mt-4 sw-mb-10 it__qg-unfollow-cayc">
+ <div className="sw-mt-4 it__qg-unfollow-cayc">
<SubHeading as="p" className="sw-mb-2 sw-body-sm">
<FormattedMessage
id="quality_gates.cayc_unfollow.description"
requiredAriaLabel={translate('field_required')}
>
<InputField
+ className="sw-mb-1"
autoComplete="off"
id="quality-gate-form-name"
maxLength={256}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+
+import { Spinner } from 'design-system';
import { clone } from 'lodash';
import * as React from 'react';
import { Helmet } from 'react-helmet-async';
import { fetchQualityGate } from '../../../api/quality-gates';
-import Spinner from '../../../components/ui/Spinner';
import { addGlobalSuccessMessage } from '../../../helpers/globalMessages';
import { translate } from '../../../helpers/l10n';
import { Condition, QualityGate } from '../../../types/types';
updatedConditionId={updatedConditionId}
/>
- <div>
+ <div className="sw-mt-10">
<div className="sw-flex sw-flex-col">
<SubTitle as="h3" className="sw-body-md-highlight">
{translate('quality_gates.projects')}
{(qualityGate.isDefault || qualityGate.isBuiltIn) && (
<div className="sw-mt-2">
- {qualityGate.isDefault && <Badge>{translate('default')}</Badge>}
+ {qualityGate.isDefault && (
+ <Badge className="sw-mr-2">{translate('default')}</Badge>
+ )}
{qualityGate.isBuiltIn && <BuiltInQualityGateBadge />}
</div>
)}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+
+import { Note } from 'design-system';
import { find, without } from 'lodash';
import * as React from 'react';
import {
renderElement = (key: string): React.ReactNode => {
const project = find(this.state.projects, { key });
return (
- <div className="select-list-list-item">
+ <div>
{project === undefined ? (
key
) : (
<>
{project.name}
<br />
- <span className="note">{project.key}</span>
+ <Note>{project.key}</Note>
</>
)}
</div>
GenericAvatar,
LabelValueSelectOption,
Modal,
+ Note,
SearchSelectDropdown,
UserGroupIcon,
} from 'design-system';
const USER_SELECT_INPUT_ID = 'quality-gate-permissions-add-modal-select-input';
export default function QualityGatePermissionsAddModalRenderer(
- props: QualityGatePermissionsAddModalRendererProps,
+ props: Readonly<QualityGatePermissionsAddModalRendererProps>,
) {
const { selection, submitting } = props;
htmlFor={USER_SELECT_INPUT_ID}
>
<SearchSelectDropdown
+ className="sw-mb-2"
controlAriaLabel={translate('quality_gates.permissions.search')}
inputId={USER_SELECT_INPUT_ID}
autoFocus
function OptionRenderer({
option,
small = false,
-}: {
+}: Readonly<{
option?: UserBase | UserGroup;
small?: boolean;
-}) {
+}>) {
if (!option) {
return null;
}
/>
<span className="sw-ml-2">
<strong className="sw-body-sm-highlight sw-mr-1">{option.name}</strong>
- {option.login}
+ <Note>{option.login}</Note>
</span>
</>
) : (
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import classNames from 'classnames';
import {
ButtonSecondary,
DangerButtonPrimary,
<SubTitle as="h3" className="sw-body-md-highlight">
{translate('quality_gates.permissions')}
</SubTitle>
- <p className="sw-body-sm sw-mb-2">{translate('quality_gates.permissions.help')}</p>
- <div>
+ <p className="sw-body-sm">{translate('quality_gates.permissions.help')}</p>
+ <div className={classNames({ 'sw-my-2': users.length + groups.length > 0 })}>
<Spinner loading={loading}>
<Table columnCount={3} columnWidths={['40px', 'auto', '1%']} width="100%">
{users.map((user) => (
</Spinner>
</div>
- <ButtonSecondary className="sw-mt-4" onClick={props.onClickAddPermission}>
+ <ButtonSecondary className="sw-mt-2" onClick={props.onClickAddPermission}>
{translate('quality_gates.permissions.grant')}
</ButtonSecondary>
*/
import styled from '@emotion/styled';
import { Checkbox, ListItem, UnorderedList, themeBorder } from 'design-system';
-import { uniqueId } from 'lodash';
import * as React from 'react';
import { translate } from '../../helpers/l10n';
import { SelectListFilter } from './SelectList';
<SelectListListElement
disabled={this.isDisabled(element)}
element={element}
- key={uniqueId()}
+ key={element}
onSelect={this.props.onSelect}
onUnselect={this.props.onUnselect}
renderElement={this.props.renderElement}