Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,33 @@ module.exports = {
packageDir: packageJsonDirectories,
},
],
'no-magic-numbers': [
'error',
{
ignore: [
// Common general-purpose values
0,
1,
-1,
2,
3,
4,
5,
6,
8,
Comment thread
MariaAga marked this conversation as resolved.
9,
// Pagination per-page options
10,
15,
20,
25,
50,
],
ignoreArrayIndexes: true,
enforceConst: true,
detectObjects: false,
},
],
'@theforeman/rules/require-ouiaid': 'error',
},
};
1 change: 1 addition & 0 deletions script/lint/lint_core_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ module.exports = {
'xml',
'xpi',
'xyz',
'uname',
'yaml',
],
minLength: 3,
Expand Down
3 changes: 2 additions & 1 deletion webpack/assets/javascripts/bundle_novnc.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ function connectFinished() {
showStatus('normal', __('Connected'));
}

const WS_ABNORMAL_CLOSURE = 1006;
function onClose(e) {
if (e.code === 1006) {
if (e.code === WS_ABNORMAL_CLOSURE) {
showStatus(
'failed',
__(
Expand Down
5 changes: 3 additions & 2 deletions webpack/assets/javascripts/dashboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ $(document).on('ContentLoad', () => {

let refreshTimeout;

const AUTO_REFRESH_INTERVAL_MS = 60000;
function autoRefresh() {
const element = $('.auto-refresh');
clearTimeout(refreshTimeout);
Expand All @@ -37,15 +38,15 @@ function autoRefresh() {
if (autoRefreshIsOn && hasFocus) {
reloadPage();
}
}, 60000);
}, AUTO_REFRESH_INTERVAL_MS);
}
}

export function startGridster() {
$('.gridster>ul')
.gridster({
widget_margins: [10, 10],
widget_base_dimensions: [94, 340],
widget_base_dimensions: [94, 340], // eslint-disable-line no-magic-numbers
max_size_x: 12,
min_cols: 12,
max_cols: 12,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ export const rtlHelpers = {
/**
* Helper to wait for async operations in tests
*/
// eslint-disable-next-line no-magic-numbers
waitForAsync: async (callback, timeout = 1000) =>
new Promise(resolve =>
setTimeout(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,11 @@ const createHostAPIRequest = async (query, array, url, dispatch, getState) => {
return onResultsError(error);
}
};
const debouncedCreateHostAPIRequest = debounce(createHostAPIRequest, 250);
const DEBOUNCE_DELAY_MS = 250;
const debouncedCreateHostAPIRequest = debounce(
createHostAPIRequest,
DEBOUNCE_DELAY_MS
);

export const onHostSearch = e => (dispatch, getState) => {
if (e.target.value === '')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import CardTemplate from '../../../../Templates/CardItem/CardTemplate';
import Slot from '../../../../../common/Slot';
import SkeletonLoader from '../../../../../common/SkeletonLoader';
import DefaultLoaderEmptyState from '../../../../DetailsCard/DefaultLoaderEmptyState';
import { STATUS } from '../../../../../../constants';
import { STATUS, MS_PER_SECOND } from '../../../../../../constants';

const ProvisioningCard = ({ status, hostDetails }) => {
const {
Expand All @@ -30,8 +30,9 @@ const ProvisioningCard = ({ status, hostDetails }) => {
round: true,
};

const BUILD_OFFSET_MS = 500000;
const getWordsDurations = duration =>
duration > 0 && duration < 1000
duration > 0 && duration < MS_PER_SECOND
? __('Less than a second')
: humanizeDuration(duration, dateOptions);

Expand All @@ -40,7 +41,9 @@ const ProvisioningCard = ({ status, hostDetails }) => {
const duration =
initiatedAt &&
installedAt &&
Math.abs(installedDate.getTime() + 500000 - initiateDate.getTime());
Math.abs(
installedDate.getTime() + BUILD_OFFSET_MS - initiateDate.getTime()
);
return (
<CardTemplate header={__('Provisioning')} expandable masonryLayout>
<DescriptionList isCompact isHorizontal>
Expand All @@ -53,7 +56,9 @@ const ProvisioningCard = ({ status, hostDetails }) => {
>
{(duration || duration === 0) && (
<Tooltip
content={`${Math.round(duration / 1000)} ${__('seconds')}`}
content={`${Math.round(duration / MS_PER_SECOND)} ${__(
'seconds'
)}`}
>
<span>{getWordsDurations(duration)}</span>
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@patternfly/react-core';
import { number_to_human_size as NumberToHumanSize } from 'number_helpers';
import { translate as __ } from '../../../../../../common/I18n';
import { BYTES_PER_KB } from '../../../../../../constants';

const VirtVmware = ({ vm }) => (
<>
Expand All @@ -21,7 +22,7 @@ const VirtVmware = ({ vm }) => (
<DescriptionListGroup>
<DescriptionListTerm>{__('Memory')}</DescriptionListTerm>
<DescriptionListDescription>
{NumberToHumanSize(vm.memory_mb * 1024 ** 2, {
{NumberToHumanSize(vm.memory_mb * BYTES_PER_KB ** 2, {
strip_insignificant_zeros: true,
})}
</DescriptionListDescription>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ export const getColumns = (fetchReports, origin) => {
there is no need to show that origin column.
*/
if (!origin) {
columns.splice(-2, 0, {
const ORIGIN_COLUMN_OFFSET = -2;
columns.splice(ORIGIN_COLUMN_OFFSET, 0, {
title: __('Origin'),
formatter: originFormatter,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import {
} from '../../../../redux/API/APISelectors';
import { useForemanSettings } from '../../../../Root/Context/ForemanContext';
import ReportsTable from './ReportsTable';
import { getControllerSearchProps } from '../../../../constants';
import {
HTTP_STATUS_CODES,
getControllerSearchProps,
} from '../../../../constants';
import PermissionDenied from '../../../PermissionDenied';

const ReportsTab = ({ hostName, origin }) => {
Expand Down Expand Up @@ -99,7 +102,7 @@ const ReportsTab = ({ hostName, origin }) => {
},
[history]
);
if (response?.status === 403) {
if (response?.status === HTTP_STATUS_CODES.FORBIDDEN) {
return <PermissionDenied missingPermissions={['view_config_reports']} />;
}
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,31 @@ import DetailTab from './Details';
import ReportsTab from './ReportsTab';
import ParametersTab from './Parameters';

const TAB_WEIGHT_OVERVIEW = 5000;
const TAB_WEIGHT_DETAILS = 4000;
const TAB_WEIGHT_PARAMETERS = 850;
const TAB_WEIGHT_REPORTS = 477;

export const registerCoreTabs = () => {
addGlobalFill(
TABS_SLOT_ID,
DEFAULT_TAB,
<OverviewTab key="host-details-overview-tab" />,
5000,
TAB_WEIGHT_OVERVIEW,
{ title: __('Overview') }
);
addGlobalFill(
TABS_SLOT_ID,
'Details',
<DetailTab key="host-details-detail-tab" />,
4000,
TAB_WEIGHT_DETAILS,
{ title: __('Details') }
);
addGlobalFill(
TABS_SLOT_ID,
'Reports',
<ReportsTab key="host-details-reports-tab" />,
477,
TAB_WEIGHT_REPORTS,
{
title: __('Reports'),
}
Expand All @@ -35,7 +40,7 @@ export const registerCoreTabs = () => {
TABS_SLOT_ID,
'Parameters',
<ParametersTab key="host-details-parameters-tab" />,
850,
TAB_WEIGHT_PARAMETERS,
{
title: __('Parameters'),
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable camelcase */
import { number_to_human_size as NumberToHumanSize } from 'number_helpers';
import { translate as __ } from '../../../common/I18n';
import { BYTES_PER_KB } from '../../../constants';

const reportedDataColumns = [
{
Expand Down Expand Up @@ -30,9 +31,12 @@ const reportedDataColumns = [
title: __('RAM'),
wrapper: hostDetails => {
if (!hostDetails?.reported_data?.ram) return null;
return NumberToHumanSize(hostDetails.reported_data.ram * 1024 * 1024, {
strip_insignificant_zeros: true,
});
return NumberToHumanSize(
hostDetails.reported_data.ram * BYTES_PER_KB * BYTES_PER_KB,
{
strip_insignificant_zeros: true,
}
);
},
isSorted: false,
weight: 1300,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Banner } from '@patternfly/react-core';

// sRGB luminance coefficients per ITU-R BT.709
const LUMINANCE_R = 0.2126;
const LUMINANCE_G = 0.7152;
const LUMINANCE_B = 0.0722;
const MAX_CHANNEL_VALUE = 255;
const LUMINANCE_THRESHOLD = 0.5;

const getContrastColor = backgroundColor => {
const hexToRgb = hex => {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
Expand All @@ -14,15 +21,13 @@ const getContrastColor = backgroundColor => {
: null;
};
backgroundColor = hexToRgb(backgroundColor);
// Calculate the relative luminance of the background color
const luminance =
(0.2126 * backgroundColor.r +
0.7152 * backgroundColor.g +
0.0722 * backgroundColor.b) /
255;
(LUMINANCE_R * backgroundColor.r +
LUMINANCE_G * backgroundColor.g +
LUMINANCE_B * backgroundColor.b) /
MAX_CHANNEL_VALUE;

// Choose black or white text based on the relative luminance
return luminance > 0.5 ? 'black' : 'white';
return luminance > LUMINANCE_THRESHOLD ? 'black' : 'white';
};
const validateHexColor = instanceColor => {
// Check if the string is a valid hex color code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import RCInputNumber from 'rc-input-number';
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { sprintf, translate as __ } from '../../common/I18n';
import { MB_FORMAT, MEGABYTES } from './constants';
import { DEFAULT_MEMORY_MB, MB_FORMAT, BYTES_PER_MB } from './constants';
import '../common/forms/NumericInput.scss';
import { noop } from '../../common/helpers';

Expand All @@ -18,24 +18,24 @@ const MemoryAllocationInput = ({
setError,
setWarning,
}) => {
const [valueMB, setValueMB] = useState(value / MEGABYTES);
const [valueMB, setValueMB] = useState(value / BYTES_PER_MB);

useEffect(() => {
const valueBytes = valueMB * MEGABYTES;
const valueBytes = valueMB * BYTES_PER_MB;
if (maxValue && valueBytes > maxValue) {
setWarning(null);
setError(
sprintf(
__('Specified value is higher than maximum value %s'),
`${maxValue / MEGABYTES} ${MB_FORMAT}`
`${maxValue / BYTES_PER_MB} ${MB_FORMAT}`
)
);
} else if (recommendedMaxValue && valueBytes > recommendedMaxValue) {
setError(null);
setWarning(
sprintf(
__('Specified value is higher than recommended maximum %s'),
`${recommendedMaxValue / MEGABYTES} ${MB_FORMAT}`
`${recommendedMaxValue / BYTES_PER_MB} ${MB_FORMAT}`
)
);
} else {
Expand All @@ -50,7 +50,7 @@ const MemoryAllocationInput = ({
v = Math.floor(valueMB / 2);
}
setValueMB(v);
onChange(v * MEGABYTES);
onChange(v * BYTES_PER_MB);
};

return (
Expand All @@ -62,13 +62,13 @@ const MemoryAllocationInput = ({
parser={str => str.replace(/\D/g, '')}
onChange={handleChange}
disabled={disabled}
min={minValue && minValue / MEGABYTES}
min={minValue && minValue / BYTES_PER_MB}
step={1}
precision={0}
name=""
prefixCls="foreman-numeric-input"
/>
<input type="hidden" name={name} value={valueMB * MEGABYTES} />
<input type="hidden" name={name} value={valueMB * BYTES_PER_MB} />
</>
);
};
Expand Down Expand Up @@ -97,7 +97,7 @@ MemoryAllocationInput.propTypes = {
};

MemoryAllocationInput.defaultProps = {
value: 2048 * MEGABYTES,
value: DEFAULT_MEMORY_MB * BYTES_PER_MB,
onChange: noop,
recommendedMaxValue: null,
maxValue: null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import { Provider } from 'react-redux';
import { MEGABYTES } from '../constants';
import { BYTES_PER_MB } from '../constants';
import MemoryAllocationInput from '../';


Expand All @@ -11,7 +11,7 @@ describe('MemoryAllocationInput', () => {
const setWarning = jest.fn();
const component = mount(
<MemoryAllocationInput
value={11264*MEGABYTES}
value={11264*BYTES_PER_MB}
recommendedMaxValue={10240}
setWarning={setWarning}
/>
Expand All @@ -23,7 +23,7 @@ describe('MemoryAllocationInput', () => {
it('error alert', async () => {
const setError = jest.fn();
const component = mount(
<MemoryAllocationInput value={21504*MEGABYTES} maxValue={20480*MEGABYTES} setError={setError} />
<MemoryAllocationInput value={21504*BYTES_PER_MB} maxValue={20480*BYTES_PER_MB} setError={setError} />
);
expect(component.find('.foreman-numeric-input-input').prop('value')).toEqual('21504 MB');
expect(setError.mock.calls.length).toBe(1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const MB_FORMAT = 'MB';

export const MEGABYTES = 1048576;
export const BYTES_PER_MB = 1048576;

export const DEFAULT_MEMORY_MB = 2048;
Loading
Loading