@@ -22,8 +22,9 @@ import { getJSON, post, postJSON, RequestData } from 'sonar-ui-common/helpers/re | |||
import throwGlobalError from '../app/utils/throwGlobalError'; | |||
import { isCategoryDefinition } from '../apps/settings/utils'; | |||
import { BranchParameters } from '../types/branch-like'; | |||
import { SettingCategoryDefinition, SettingDefinition, SettingValue } from '../types/settings'; | |||
export function getDefinitions(component?: string): Promise<T.SettingCategoryDefinition[]> { | |||
export function getDefinitions(component?: string): Promise<SettingCategoryDefinition[]> { | |||
return getJSON('/api/settings/list_definitions', { component }).then( | |||
r => r.definitions, | |||
throwGlobalError | |||
@@ -32,12 +33,12 @@ export function getDefinitions(component?: string): Promise<T.SettingCategoryDef | |||
export function getValues( | |||
data: { keys: string; component?: string } & BranchParameters | |||
): Promise<T.SettingValue[]> { | |||
): Promise<SettingValue[]> { | |||
return getJSON('/api/settings/values', data).then(r => r.settings); | |||
} | |||
export function setSettingValue( | |||
definition: T.SettingDefinition, | |||
definition: SettingDefinition, | |||
value: any, | |||
component?: string | |||
): Promise<void> { |
@@ -17,14 +17,19 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { | |||
Setting, | |||
SettingCategoryDefinition, | |||
SettingFieldDefinition | |||
} from '../../../types/settings'; | |||
import { getDefaultValue, getEmptyValue, sanitizeTranslation } from '../utils'; | |||
const fields = [ | |||
{ key: 'foo', type: 'STRING' } as T.SettingFieldDefinition, | |||
{ key: 'bar', type: 'SINGLE_SELECT_LIST' } as T.SettingFieldDefinition | |||
{ key: 'foo', type: 'STRING' } as SettingFieldDefinition, | |||
{ key: 'bar', type: 'SINGLE_SELECT_LIST' } as SettingFieldDefinition | |||
]; | |||
const settingDefinition: T.SettingCategoryDefinition = { | |||
const settingDefinition: SettingCategoryDefinition = { | |||
category: 'test', | |||
fields: [], | |||
key: 'test', | |||
@@ -34,7 +39,7 @@ const settingDefinition: T.SettingCategoryDefinition = { | |||
describe('#getEmptyValue()', () => { | |||
it('should work for property sets', () => { | |||
const setting: T.SettingCategoryDefinition = { | |||
const setting: SettingCategoryDefinition = { | |||
...settingDefinition, | |||
type: 'PROPERTY_SET', | |||
fields | |||
@@ -43,7 +48,7 @@ describe('#getEmptyValue()', () => { | |||
}); | |||
it('should work for multi values string', () => { | |||
const setting: T.SettingCategoryDefinition = { | |||
const setting: SettingCategoryDefinition = { | |||
...settingDefinition, | |||
type: 'STRING', | |||
multiValues: true | |||
@@ -52,7 +57,7 @@ describe('#getEmptyValue()', () => { | |||
}); | |||
it('should work for multi values boolean', () => { | |||
const setting: T.SettingCategoryDefinition = { | |||
const setting: SettingCategoryDefinition = { | |||
...settingDefinition, | |||
type: 'BOOLEAN', | |||
multiValues: true | |||
@@ -62,19 +67,20 @@ describe('#getEmptyValue()', () => { | |||
}); | |||
describe('#getDefaultValue()', () => { | |||
const check = (parentValue?: string, expected?: string) => { | |||
const setting: T.Setting = { | |||
definition: { key: 'test', options: [], type: 'BOOLEAN' }, | |||
parentValue, | |||
key: 'test' | |||
}; | |||
expect(getDefaultValue(setting)).toEqual(expected); | |||
}; | |||
it('should work for boolean field when passing "true"', () => | |||
check('true', 'settings.boolean.true')); | |||
it('should work for boolean field when passing "false"', () => | |||
check('false', 'settings.boolean.false')); | |||
it.each([ | |||
['true', 'settings.boolean.true'], | |||
['false', 'settings.boolean.false'] | |||
])( | |||
'should work for boolean field when passing "%s"', | |||
(parentValue?: string, expected?: string) => { | |||
const setting: Setting = { | |||
definition: { key: 'test', options: [], type: 'BOOLEAN' }, | |||
parentValue, | |||
key: 'test' | |||
}; | |||
expect(getDefaultValue(setting)).toEqual(expected); | |||
} | |||
); | |||
}); | |||
describe('sanitizeTranslation', () => { |
@@ -29,6 +29,7 @@ import { | |||
isSettingsAppLoading, | |||
Store | |||
} from '../../../store/rootReducer'; | |||
import { Setting } from '../../../types/settings'; | |||
import { checkValue, resetValue, saveValue } from '../store/actions'; | |||
import { cancelChange, changeValue, passValidation } from '../store/settingsPage'; | |||
import { | |||
@@ -51,7 +52,7 @@ interface Props { | |||
passValidation: (key: string) => void; | |||
resetValue: (key: string, component?: string) => Promise<void>; | |||
saveValue: (key: string, component?: string) => Promise<void>; | |||
setting: T.Setting; | |||
setting: Setting; | |||
validationMessage?: string; | |||
} | |||
@@ -59,6 +60,8 @@ interface State { | |||
success: boolean; | |||
} | |||
const SAFE_SET_STATE_DELAY = 3000; | |||
export class Definition extends React.PureComponent<Props, State> { | |||
timeout?: number; | |||
mounted = false; | |||
@@ -91,7 +94,10 @@ export class Definition extends React.PureComponent<Props, State> { | |||
return this.props.resetValue(definition.key, componentKey).then(() => { | |||
this.props.cancelChange(definition.key); | |||
this.safeSetState({ success: true }); | |||
this.timeout = window.setTimeout(() => this.safeSetState({ success: false }), 3000); | |||
this.timeout = window.setTimeout( | |||
() => this.safeSetState({ success: false }), | |||
SAFE_SET_STATE_DELAY | |||
); | |||
}); | |||
}; | |||
@@ -113,9 +119,14 @@ export class Definition extends React.PureComponent<Props, State> { | |||
this.props.saveValue(setting.definition.key, component && component.key).then( | |||
() => { | |||
this.safeSetState({ success: true }); | |||
this.timeout = window.setTimeout(() => this.safeSetState({ success: false }), 3000); | |||
this.timeout = window.setTimeout( | |||
() => this.safeSetState({ success: false }), | |||
SAFE_SET_STATE_DELAY | |||
); | |||
}, | |||
() => {} | |||
() => { | |||
/* Do nothing */ | |||
} | |||
); | |||
} | |||
}; |
@@ -21,6 +21,7 @@ import * as React from 'react'; | |||
import { Button, ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons'; | |||
import Modal from 'sonar-ui-common/components/controls/Modal'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { Setting } from '../../../types/settings'; | |||
import { getDefaultValue, getSettingValue, isEmptyValue } from '../utils'; | |||
type Props = { | |||
@@ -31,7 +32,7 @@ type Props = { | |||
onCancel: () => void; | |||
onReset: () => void; | |||
onSave: () => void; | |||
setting: T.Setting; | |||
setting: Setting; | |||
}; | |||
type State = { reseting: boolean }; |
@@ -18,11 +18,12 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { Setting } from '../../../types/settings'; | |||
import Definition from './Definition'; | |||
interface Props { | |||
component?: T.Component; | |||
settings: T.Setting[]; | |||
settings: Setting[]; | |||
} | |||
export default function DefinitionsList({ component, settings }: Props) { |
@@ -19,6 +19,7 @@ | |||
*/ | |||
import { groupBy, isEqual, sortBy } from 'lodash'; | |||
import * as React from 'react'; | |||
import { Setting, SettingCategoryDefinition } from '../../../types/settings'; | |||
import { getSubCategoryDescription, getSubCategoryName, sanitizeTranslation } from '../utils'; | |||
import DefinitionsList from './DefinitionsList'; | |||
import EmailForm from './EmailForm'; | |||
@@ -27,7 +28,7 @@ interface Props { | |||
category: string; | |||
component?: T.Component; | |||
fetchValues: Function; | |||
settings: Array<T.Setting & { definition: T.SettingCategoryDefinition }>; | |||
settings: Array<Setting & { definition: SettingCategoryDefinition }>; | |||
subCategory?: string; | |||
} | |||
@@ -20,9 +20,10 @@ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | |||
import { Setting } from '../../../../types/settings'; | |||
import { Definition } from '../Definition'; | |||
const setting: T.Setting = { | |||
const setting: Setting = { | |||
key: 'foo', | |||
value: '42', | |||
inherited: true, | |||
@@ -35,6 +36,14 @@ const setting: T.Setting = { | |||
} | |||
}; | |||
beforeAll(() => { | |||
jest.useFakeTimers(); | |||
}); | |||
afterAll(() => { | |||
jest.useRealTimers(); | |||
}); | |||
it('should render correctly', () => { | |||
const wrapper = shallowRender(); | |||
expect(wrapper).toMatchSnapshot(); | |||
@@ -65,10 +74,26 @@ it('should correctly save value change', async () => { | |||
await waitAndUpdate(wrapper); | |||
expect(saveValue).toHaveBeenCalledWith(setting.definition.key, undefined); | |||
expect(wrapper.find('AlertSuccessIcon').exists()).toBe(true); | |||
expect(wrapper.state().success).toBe(true); | |||
jest.runAllTimers(); | |||
expect(wrapper.state().success).toBe(false); | |||
}); | |||
it('should correctly reset', async () => { | |||
const cancelChange = jest.fn(); | |||
const resetValue = jest.fn().mockResolvedValue({}); | |||
const wrapper = shallowRender({ cancelChange, changedValue: 10, resetValue }); | |||
wrapper.find('DefinitionActions').prop<Function>('onReset')(); | |||
await waitAndUpdate(wrapper); | |||
expect(resetValue).toHaveBeenCalledWith(setting.definition.key, undefined); | |||
expect(cancelChange).toHaveBeenCalledWith(setting.definition.key); | |||
expect(wrapper.state().success).toBe(true); | |||
jest.runAllTimers(); | |||
expect(wrapper.state().success).toBe(false); | |||
}); | |||
function shallowRender(props: Partial<Definition['props']> = {}) { | |||
return shallow( | |||
return shallow<Definition>( | |||
<Definition | |||
cancelChange={jest.fn()} | |||
changeValue={jest.fn()} |
@@ -19,9 +19,10 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { SettingCategoryDefinition } from '../../../../types/settings'; | |||
import DefinitionActions from '../DefinitionActions'; | |||
const definition: T.SettingCategoryDefinition = { | |||
const definition: SettingCategoryDefinition = { | |||
category: 'baz', | |||
description: 'lorem', | |||
fields: [], |
@@ -19,9 +19,10 @@ | |||
*/ | |||
import * as React from 'react'; | |||
import Select from 'sonar-ui-common/components/controls/Select'; | |||
import { SettingCategoryDefinition } from '../../../../types/settings'; | |||
import { DefaultSpecializedInputProps } from '../../utils'; | |||
type Props = DefaultSpecializedInputProps & Pick<T.SettingCategoryDefinition, 'options'>; | |||
type Props = DefaultSpecializedInputProps & Pick<SettingCategoryDefinition, 'options'>; | |||
export default class InputForSingleSelectList extends React.PureComponent<Props> { | |||
handleInputChange = ({ value }: { value: string }) => { |
@@ -18,6 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { SettingType } from '../../../../types/settings'; | |||
import { | |||
DefaultInputProps, | |||
DefaultSpecializedInputProps, | |||
@@ -32,10 +33,11 @@ import InputForString from './InputForString'; | |||
import InputForText from './InputForText'; | |||
const typeMapping: { | |||
[type in T.SettingType]?: React.ComponentType<DefaultSpecializedInputProps>; | |||
[type in SettingType]?: React.ComponentType<DefaultSpecializedInputProps>; | |||
} = { | |||
STRING: InputForString, | |||
TEXT: InputForText, | |||
JSON: InputForText, | |||
PASSWORD: InputForPassword, | |||
BOOLEAN: InputForBoolean, | |||
INTEGER: InputForNumber, |
@@ -19,6 +19,7 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { Setting, SettingCategoryDefinition } from '../../../../../types/settings'; | |||
import { DefaultInputProps } from '../../../utils'; | |||
import Input from '../Input'; | |||
@@ -26,7 +27,7 @@ const settingValue = { | |||
key: 'example' | |||
}; | |||
const settingDefinition: T.SettingCategoryDefinition = { | |||
const settingDefinition: SettingCategoryDefinition = { | |||
category: 'general', | |||
fields: [], | |||
key: 'example', | |||
@@ -57,7 +58,7 @@ it('should render MultiValueInput', () => { | |||
}); | |||
it('should render PropertySetInput', () => { | |||
const setting: T.Setting = { | |||
const setting: Setting = { | |||
...settingValue, | |||
definition: { ...settingDefinition, type: 'PROPERTY_SET' } | |||
}; |
@@ -20,6 +20,7 @@ | |||
import { shallow, ShallowWrapper } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { click } from 'sonar-ui-common/helpers/testUtils'; | |||
import { SettingCategoryDefinition } from '../../../../../types/settings'; | |||
import { DefaultInputProps } from '../../../utils'; | |||
import MultiValueInput from '../MultiValueInput'; | |||
import PrimitiveInput from '../PrimitiveInput'; | |||
@@ -28,7 +29,7 @@ const settingValue = { | |||
key: 'example' | |||
}; | |||
const settingDefinition: T.SettingCategoryDefinition = { | |||
const settingDefinition: SettingCategoryDefinition = { | |||
category: 'general', | |||
fields: [], | |||
key: 'example', |
@@ -17,7 +17,11 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { fetchSettings } from '../actions'; | |||
import { | |||
getSettingsAppChangedValue, | |||
getSettingsAppDefinition | |||
} from '../../../../store/rootReducer'; | |||
import { checkValue, fetchSettings } from '../actions'; | |||
import { receiveDefinitions } from '../definitions'; | |||
jest.mock('../../../../api/settings', () => ({ | |||
@@ -37,6 +41,11 @@ jest.mock('../definitions', () => ({ | |||
receiveDefinitions: jest.fn() | |||
})); | |||
jest.mock('../../../../store/rootReducer', () => ({ | |||
getSettingsAppDefinition: jest.fn(), | |||
getSettingsAppChangedValue: jest.fn() | |||
})); | |||
it('#fetchSettings should filter LICENSE type settings', async () => { | |||
const dispatch = jest.fn(); | |||
@@ -49,3 +58,88 @@ it('#fetchSettings should filter LICENSE type settings', async () => { | |||
} | |||
]); | |||
}); | |||
describe('checkValue', () => { | |||
const dispatch = jest.fn(); | |||
beforeEach(() => { | |||
jest.clearAllMocks(); | |||
}); | |||
it('should correctly identify empty strings', () => { | |||
(getSettingsAppDefinition as jest.Mock).mockReturnValue({ | |||
defaultValue: 'hello', | |||
type: 'TEXT' | |||
}); | |||
(getSettingsAppChangedValue as jest.Mock).mockReturnValue(undefined); | |||
const key = 'key'; | |||
expect(checkValue(key)(dispatch, jest.fn())).toBe(false); | |||
expect(dispatch).toBeCalledWith({ | |||
type: 'settingsPage/FAIL_VALIDATION', | |||
key, | |||
message: 'settings.state.value_cant_be_empty' | |||
}); | |||
}); | |||
it('should correctly identify empty with no default', () => { | |||
(getSettingsAppDefinition as jest.Mock).mockReturnValue({ | |||
type: 'TEXT' | |||
}); | |||
(getSettingsAppChangedValue as jest.Mock).mockReturnValue(undefined); | |||
const key = 'key'; | |||
expect(checkValue(key)(dispatch, jest.fn())).toBe(false); | |||
expect(dispatch).toBeCalledWith({ | |||
type: 'settingsPage/FAIL_VALIDATION', | |||
key, | |||
message: 'settings.state.value_cant_be_empty_no_default' | |||
}); | |||
}); | |||
it('should correctly identify non-empty strings', () => { | |||
(getSettingsAppDefinition as jest.Mock).mockReturnValue({ | |||
type: 'TEXT' | |||
}); | |||
(getSettingsAppChangedValue as jest.Mock).mockReturnValue('not empty'); | |||
const key = 'key'; | |||
expect(checkValue(key)(dispatch, jest.fn())).toBe(true); | |||
expect(dispatch).toBeCalledWith({ | |||
type: 'settingsPage/PASS_VALIDATION', | |||
key | |||
}); | |||
}); | |||
it('should correctly identify misformed JSON', () => { | |||
(getSettingsAppDefinition as jest.Mock).mockReturnValue({ | |||
type: 'JSON' | |||
}); | |||
(getSettingsAppChangedValue as jest.Mock).mockReturnValue('{JSON: "asd;{'); | |||
const key = 'key'; | |||
expect(checkValue(key)(dispatch, jest.fn())).toBe(false); | |||
expect(dispatch).toBeCalledWith({ | |||
type: 'settingsPage/FAIL_VALIDATION', | |||
key, | |||
message: 'Unexpected token J in JSON at position 1' | |||
}); | |||
}); | |||
it('should correctly identify correct JSON', () => { | |||
(getSettingsAppDefinition as jest.Mock).mockReturnValue({ | |||
type: 'JSON' | |||
}); | |||
(getSettingsAppChangedValue as jest.Mock).mockReturnValue( | |||
'{"number": 42, "question": "answer"}' | |||
); | |||
const key = 'key'; | |||
expect(checkValue(key)(dispatch, jest.fn())).toBe(true); | |||
expect(dispatch).toBeCalledWith({ | |||
type: 'settingsPage/PASS_VALIDATION', | |||
key | |||
}); | |||
}); | |||
}); |
@@ -75,6 +75,15 @@ export function checkValue(key: string) { | |||
return false; | |||
} | |||
if (definition.type === 'JSON') { | |||
try { | |||
JSON.parse(value); | |||
} catch (e) { | |||
dispatch(failValidation(key, e.message)); | |||
return false; | |||
} | |||
} | |||
dispatch(passValidation(key)); | |||
return true; | |||
}; |
@@ -19,6 +19,7 @@ | |||
*/ | |||
import { keyBy, sortBy, uniqBy } from 'lodash'; | |||
import { ActionType } from '../../../store/utils/actions'; | |||
import { SettingCategoryDefinition } from '../../../types/settings'; | |||
import { DEFAULT_CATEGORY, getCategoryName } from '../utils'; | |||
const enum Actions { | |||
@@ -27,9 +28,9 @@ const enum Actions { | |||
type Action = ActionType<typeof receiveDefinitions, Actions.ReceiveDefinitions>; | |||
export type State = T.Dict<T.SettingCategoryDefinition>; | |||
export type State = T.Dict<SettingCategoryDefinition>; | |||
export function receiveDefinitions(definitions: T.SettingCategoryDefinition[]) { | |||
export function receiveDefinitions(definitions: SettingCategoryDefinition[]) { | |||
return { type: Actions.ReceiveDefinitions, definitions }; | |||
} | |||
@@ -21,6 +21,7 @@ import { keyBy } from 'lodash'; | |||
import { combineReducers } from 'redux'; | |||
import { Action as AppStateAction, Actions as AppStateActions } from '../../../store/appState'; | |||
import { ActionType } from '../../../store/utils/actions'; | |||
import { SettingValue } from '../../../types/settings'; | |||
enum Actions { | |||
receiveValues = 'RECEIVE_VALUES' | |||
@@ -28,7 +29,7 @@ enum Actions { | |||
type Action = ActionType<typeof receiveValues, Actions.receiveValues>; | |||
type SettingsState = T.Dict<T.SettingValue>; | |||
type SettingsState = T.Dict<SettingValue>; | |||
export interface State { | |||
components: T.Dict<SettingsState>; | |||
@@ -74,11 +75,7 @@ function global(state: State['components'] = {}, action: Action | AppStateAction | |||
export default combineReducers({ components, global }); | |||
export function getValue( | |||
state: State, | |||
key: string, | |||
component?: string | |||
): T.SettingValue | undefined { | |||
export function getValue(state: State, key: string, component?: string): SettingValue | undefined { | |||
if (component) { | |||
return state.components[component] && state.components[component][key]; | |||
} |
@@ -19,6 +19,7 @@ | |||
*/ | |||
import { sanitize } from 'dompurify'; | |||
import { hasMessage, translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { Setting, SettingCategoryDefinition, SettingDefinition } from '../../types/settings'; | |||
export const DEFAULT_CATEGORY = 'general'; | |||
@@ -32,7 +33,7 @@ export interface DefaultInputProps { | |||
onCancel?: () => void; | |||
onChange: (value: any) => void; | |||
onSave?: () => void; | |||
setting: T.Setting; | |||
setting: Setting; | |||
value: any; | |||
} | |||
@@ -42,12 +43,12 @@ export function sanitizeTranslation(html: string) { | |||
}); | |||
} | |||
export function getPropertyName(definition: T.SettingDefinition) { | |||
export function getPropertyName(definition: SettingDefinition) { | |||
const key = `property.${definition.key}.name`; | |||
return hasMessage(key) ? translate(key) : definition.name; | |||
} | |||
export function getPropertyDescription(definition: T.SettingDefinition) { | |||
export function getPropertyDescription(definition: SettingDefinition) { | |||
const key = `property.${definition.key}.description`; | |||
return hasMessage(key) ? translate(key) : definition.description; | |||
} | |||
@@ -67,12 +68,12 @@ export function getSubCategoryDescription(category: string, subCategory: string) | |||
return hasMessage(key) ? translate(key) : null; | |||
} | |||
export function getUniqueName(definition: T.SettingDefinition, index?: string) { | |||
export function getUniqueName(definition: SettingDefinition, index?: string) { | |||
const indexSuffix = index ? `[${index}]` : ''; | |||
return `settings[${definition.key}]${indexSuffix}`; | |||
} | |||
export function getSettingValue({ definition, fieldValues, value, values }: T.Setting) { | |||
export function getSettingValue({ definition, fieldValues, value, values }: Setting) { | |||
if (isCategoryDefinition(definition) && definition.multiValues) { | |||
return values; | |||
} else if (definition.type === 'PROPERTY_SET') { | |||
@@ -82,7 +83,7 @@ export function getSettingValue({ definition, fieldValues, value, values }: T.Se | |||
} | |||
} | |||
export function isEmptyValue(definition: T.SettingDefinition, value: any) { | |||
export function isEmptyValue(definition: SettingDefinition, value: any) { | |||
if (value == null) { | |||
return true; | |||
} else if (definition.type === 'BOOLEAN') { | |||
@@ -92,13 +93,11 @@ export function isEmptyValue(definition: T.SettingDefinition, value: any) { | |||
} | |||
} | |||
export function isCategoryDefinition( | |||
item: T.SettingDefinition | |||
): item is T.SettingCategoryDefinition { | |||
export function isCategoryDefinition(item: SettingDefinition): item is SettingCategoryDefinition { | |||
return Boolean((item as any).fields); | |||
} | |||
export function getEmptyValue(item: T.SettingDefinition | T.SettingCategoryDefinition): any { | |||
export function getEmptyValue(item: SettingDefinition | SettingCategoryDefinition): any { | |||
if (isCategoryDefinition(item)) { | |||
if (item.multiValues) { | |||
return [getEmptyValue({ ...item, multiValues: false })]; | |||
@@ -117,11 +116,11 @@ export function getEmptyValue(item: T.SettingDefinition | T.SettingCategoryDefin | |||
return ''; | |||
} | |||
export function isDefaultOrInherited(setting: T.Setting) { | |||
export function isDefaultOrInherited(setting: Setting) { | |||
return Boolean(setting.inherited); | |||
} | |||
export function getDefaultValue(setting: T.Setting) { | |||
export function getDefaultValue(setting: Setting) { | |||
const { definition, parentFieldValues, parentValue, parentValues } = setting; | |||
if (definition.type === 'PASSWORD') { |
@@ -22,3 +22,52 @@ export const enum SettingsKey { | |||
DefaultProjectVisibility = 'projects.default.visibility', | |||
ServerBaseUrl = 'sonar.core.serverBaseURL' | |||
} | |||
export type Setting = SettingValue & { definition: SettingDefinition }; | |||
export type SettingType = | |||
| 'STRING' | |||
| 'TEXT' | |||
| 'JSON' | |||
| 'PASSWORD' | |||
| 'BOOLEAN' | |||
| 'FLOAT' | |||
| 'INTEGER' | |||
| 'LICENSE' | |||
| 'LONG' | |||
| 'SINGLE_SELECT_LIST' | |||
| 'PROPERTY_SET'; | |||
export interface SettingDefinition { | |||
description?: string; | |||
key: string; | |||
multiValues?: boolean; | |||
name?: string; | |||
options: string[]; | |||
type?: SettingType; | |||
} | |||
export interface SettingFieldDefinition extends SettingDefinition { | |||
description: string; | |||
name: string; | |||
} | |||
export interface SettingCategoryDefinition extends SettingDefinition { | |||
category: string; | |||
defaultValue?: string; | |||
deprecatedKey?: string; | |||
fields: SettingFieldDefinition[]; | |||
multiValues?: boolean; | |||
subCategory: string; | |||
} | |||
export interface SettingValue { | |||
fieldValues?: Array<T.Dict<string>>; | |||
inherited?: boolean; | |||
key: string; | |||
parentFieldValues?: Array<T.Dict<string>>; | |||
parentValue?: string; | |||
parentValues?: string[]; | |||
value?: string; | |||
values?: string[]; | |||
} |
@@ -672,54 +672,6 @@ declare namespace T { | |||
export type RuleType = 'BUG' | 'VULNERABILITY' | 'CODE_SMELL' | 'SECURITY_HOTSPOT' | 'UNKNOWN'; | |||
export type Setting = SettingValue & { definition: SettingDefinition }; | |||
export type SettingType = | |||
| 'STRING' | |||
| 'TEXT' | |||
| 'PASSWORD' | |||
| 'BOOLEAN' | |||
| 'FLOAT' | |||
| 'INTEGER' | |||
| 'LICENSE' | |||
| 'LONG' | |||
| 'SINGLE_SELECT_LIST' | |||
| 'PROPERTY_SET'; | |||
export interface SettingDefinition { | |||
description?: string; | |||
key: string; | |||
multiValues?: boolean; | |||
name?: string; | |||
options: string[]; | |||
type?: SettingType; | |||
} | |||
export interface SettingFieldDefinition extends SettingDefinition { | |||
description: string; | |||
name: string; | |||
} | |||
export interface SettingCategoryDefinition extends SettingDefinition { | |||
category: string; | |||
defaultValue?: string; | |||
deprecatedKey?: string; | |||
fields: SettingFieldDefinition[]; | |||
multiValues?: boolean; | |||
subCategory: string; | |||
} | |||
export interface SettingValue { | |||
fieldValues?: Array<T.Dict<string>>; | |||
inherited?: boolean; | |||
key: string; | |||
parentFieldValues?: Array<T.Dict<string>>; | |||
parentValue?: string; | |||
parentValues?: string[]; | |||
value?: string; | |||
values?: string[]; | |||
} | |||
export interface Snippet { | |||
start: number; | |||
end: number; |