@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { getJSON, post, postJSON } from 'sonar-ui-common/helpers/request'; | |||
import { getJSON } from 'sonar-ui-common/helpers/request'; | |||
import throwGlobalError from '../app/utils/throwGlobalError'; | |||
import { BranchParameters } from '../types/branch-like'; | |||
import { | |||
@@ -82,36 +82,3 @@ export function getMeasuresForProjects( | |||
metricKeys: metricKeys.join() | |||
}).then(r => r.measures); | |||
} | |||
export function getCustomMeasures(data: { | |||
f?: string; | |||
p?: number; | |||
projectKey: string; | |||
ps?: number; | |||
}): Promise<{ customMeasures: T.CustomMeasure[]; paging: T.Paging }> { | |||
return getJSON('/api/custom_measures/search', data).then( | |||
r => | |||
({ | |||
customMeasures: r.customMeasures, | |||
paging: { pageIndex: r.p, pageSize: r.ps, total: r.total } | |||
} as any), | |||
throwGlobalError | |||
); | |||
} | |||
export function createCustomMeasure(data: { | |||
description?: string; | |||
metricKey: string; | |||
projectKey: string; | |||
value: string; | |||
}): Promise<T.CustomMeasure> { | |||
return postJSON('/api/custom_measures/create', data).catch(throwGlobalError); | |||
} | |||
export function updateCustomMeasure(data: { description?: string; id: string; value?: string }) { | |||
return post('/api/custom_measures/update', data).catch(throwGlobalError); | |||
} | |||
export function deleteCustomMeasure(data: { id: string }) { | |||
return post('/api/custom_measures/delete', data).catch(throwGlobalError); | |||
} |
@@ -28,7 +28,6 @@ import NavBarTabs from 'sonar-ui-common/components/ui/NavBarTabs'; | |||
import { hasMessage, translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { withAppState } from '../../../../components/hoc/withAppState'; | |||
import { getBranchLikeQuery, isPullRequest } from '../../../../helpers/branch-like'; | |||
import { isSonarCloud } from '../../../../helpers/system'; | |||
import { getPortfolioUrl, getProjectQueryUrl } from '../../../../helpers/urls'; | |||
import { BranchLike, BranchParameters } from '../../../../types/branch-like'; | |||
import { ComponentQualifier, isPortfolioLike } from '../../../../types/component'; | |||
@@ -42,7 +41,6 @@ const SETTINGS_URLS = [ | |||
'/project/settings', | |||
'/project/quality_profiles', | |||
'/project/quality_gate', | |||
'/custom_measures', | |||
'/project/links', | |||
'/project_roles', | |||
'/project/history', | |||
@@ -296,7 +294,6 @@ export class Menu extends React.PureComponent<Props> { | |||
...this.renderAdminExtensions(query, isApplication), | |||
this.renderProfilesLink(query), | |||
this.renderQualityGateLink(query), | |||
this.renderCustomMeasuresLink(query), | |||
this.renderLinksLink(query), | |||
this.renderPermissionsLink(query), | |||
this.renderBackgroundTasksLink(query), | |||
@@ -414,19 +411,6 @@ export class Menu extends React.PureComponent<Props> { | |||
); | |||
}; | |||
renderCustomMeasuresLink = (query: Query) => { | |||
if (isSonarCloud() || !this.getConfiguration().showManualMeasures) { | |||
return null; | |||
} | |||
return ( | |||
<li key="custom_measures"> | |||
<Link activeClassName="active" to={{ pathname: '/custom_measures', query }}> | |||
{translate('custom_measures.page')} | |||
</Link> | |||
</li> | |||
); | |||
}; | |||
renderLinksLink = (query: Query) => { | |||
if (!this.getConfiguration().showLinks) { | |||
return null; |
@@ -36,7 +36,6 @@ import backgroundTasksRoutes from '../../apps/background-tasks/routes'; | |||
import codeRoutes from '../../apps/code/routes'; | |||
import codingRulesRoutes from '../../apps/coding-rules/routes'; | |||
import componentMeasuresRoutes from '../../apps/component-measures/routes'; | |||
import customMeasuresRoutes from '../../apps/custom-measures/routes'; | |||
import customMetricsRoutes from '../../apps/custom-metrics/routes'; | |||
import documentationRoutes from '../../apps/documentation/routes'; | |||
import groupsRoutes from '../../apps/groups/routes'; | |||
@@ -192,7 +191,6 @@ function renderComponentRoutes() { | |||
/> | |||
<RouteWithChildRoutes path="tutorials" childRoutes={tutorialsRoutes} /> | |||
<Route component={lazyLoadComponent(() => import('../components/ProjectAdminContainer'))}> | |||
<RouteWithChildRoutes path="custom_measures" childRoutes={customMeasuresRoutes} /> | |||
<Route | |||
path="project/admin/extension/:pluginKey/:extensionKey" | |||
component={lazyLoadComponent(() => |
@@ -1,159 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { Helmet } from 'react-helmet-async'; | |||
import ListFooter from 'sonar-ui-common/components/controls/ListFooter'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { | |||
createCustomMeasure, | |||
deleteCustomMeasure, | |||
getCustomMeasures, | |||
updateCustomMeasure | |||
} from '../../../api/measures'; | |||
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; | |||
import Header from './Header'; | |||
import List from './List'; | |||
interface Props { | |||
component: { key: string }; | |||
} | |||
interface State { | |||
loading: boolean; | |||
measures?: T.CustomMeasure[]; | |||
paging?: T.Paging; | |||
} | |||
const PAGE_SIZE = 50; | |||
export default class App extends React.PureComponent<Props, State> { | |||
mounted = false; | |||
state: State = { loading: true }; | |||
componentDidMount() { | |||
this.mounted = true; | |||
this.fetchMeasures(); | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
fetchMeasures = () => { | |||
this.setState({ loading: true }); | |||
getCustomMeasures({ projectKey: this.props.component.key, ps: PAGE_SIZE }).then( | |||
({ customMeasures, paging }) => { | |||
if (this.mounted) { | |||
this.setState({ loading: false, measures: customMeasures, paging }); | |||
} | |||
}, | |||
this.stopLoading | |||
); | |||
}; | |||
fetchMore = () => { | |||
const { paging } = this.state; | |||
if (paging) { | |||
this.setState({ loading: true }); | |||
getCustomMeasures({ | |||
projectKey: this.props.component.key, | |||
p: paging.pageIndex + 1, | |||
ps: PAGE_SIZE | |||
}).then(({ customMeasures, paging }) => { | |||
if (this.mounted) { | |||
this.setState(({ measures = [] }: State) => ({ | |||
loading: false, | |||
measures: [...measures, ...customMeasures], | |||
paging | |||
})); | |||
} | |||
}, this.stopLoading); | |||
} | |||
}; | |||
stopLoading = () => { | |||
if (this.mounted) { | |||
this.setState({ loading: false }); | |||
} | |||
}; | |||
handleCreate = (data: { description: string; metricKey: string; value: string }) => { | |||
return createCustomMeasure({ ...data, projectKey: this.props.component.key }).then(measure => { | |||
if (this.mounted) { | |||
this.setState(({ measures = [], paging }: State) => ({ | |||
measures: [...measures, measure], | |||
paging: paging && { ...paging, total: paging.total + 1 } | |||
})); | |||
} | |||
}); | |||
}; | |||
handleEdit = (data: { description: string; id: string; value: string }) => { | |||
return updateCustomMeasure(data).then(() => { | |||
if (this.mounted) { | |||
this.setState(({ measures = [] }: State) => ({ | |||
measures: measures.map(measure => | |||
measure.id === data.id ? { ...measure, ...data } : measure | |||
) | |||
})); | |||
} | |||
}); | |||
}; | |||
handleDelete = (measureId: string) => { | |||
return deleteCustomMeasure({ id: measureId }).then(() => { | |||
if (this.mounted) { | |||
this.setState(({ measures = [], paging }: State) => ({ | |||
measures: measures.filter(measure => measure.id !== measureId), | |||
paging: paging && { ...paging, total: paging.total - 1 } | |||
})); | |||
} | |||
}); | |||
}; | |||
render() { | |||
const { loading, measures, paging } = this.state; | |||
return ( | |||
<> | |||
<Suggestions suggestions="custom_measures" /> | |||
<Helmet title={translate('custom_measures.page')} /> | |||
<div className="page page-limited"> | |||
<Header | |||
loading={loading} | |||
onCreate={this.handleCreate} | |||
skipMetrics={measures && measures.map(measure => measure.metric.key)} | |||
/> | |||
{measures && ( | |||
<List measures={measures} onDelete={this.handleDelete} onEdit={this.handleEdit} /> | |||
)} | |||
{measures && paging && ( | |||
<ListFooter | |||
count={measures.length} | |||
loadMore={this.fetchMore} | |||
ready={!loading} | |||
total={paging.total} | |||
/> | |||
)} | |||
</div> | |||
</> | |||
); | |||
} | |||
} |
@@ -1,74 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { Button } from 'sonar-ui-common/components/controls/buttons'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import Form from './Form'; | |||
interface Props { | |||
onCreate: (data: { description: string; metricKey: string; value: string }) => Promise<void>; | |||
skipMetrics: string[] | undefined; | |||
} | |||
interface State { | |||
modal: boolean; | |||
} | |||
export default class CreateButton extends React.PureComponent<Props, State> { | |||
mounted = false; | |||
state: State = { modal: false }; | |||
componentDidMount() { | |||
this.mounted = true; | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
handleClick = () => { | |||
this.setState({ modal: true }); | |||
}; | |||
handleClose = () => { | |||
if (this.mounted) { | |||
this.setState({ modal: false }); | |||
} | |||
}; | |||
render() { | |||
return ( | |||
<> | |||
<Button id="custom-measures-create" onClick={this.handleClick}> | |||
{translate('create')} | |||
</Button> | |||
{this.state.modal && ( | |||
<Form | |||
confirmButtonText={translate('create')} | |||
header={translate('custom_measures.create_custom_measure')} | |||
onClose={this.handleClose} | |||
onSubmit={this.props.onCreate} | |||
skipMetrics={this.props.skipMetrics} | |||
/> | |||
)} | |||
</> | |||
); | |||
} | |||
} |
@@ -1,63 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons'; | |||
import SimpleModal from 'sonar-ui-common/components/controls/SimpleModal'; | |||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n'; | |||
interface Props { | |||
measure: T.CustomMeasure; | |||
onClose: () => void; | |||
onSubmit: () => Promise<void>; | |||
} | |||
export default function DeleteForm({ measure, onClose, onSubmit }: Props) { | |||
const header = translate('custom_measures.delete_custom_measure'); | |||
return ( | |||
<SimpleModal header={header} onClose={onClose} onSubmit={onSubmit}> | |||
{({ onCloseClick, onFormSubmit, submitting }) => ( | |||
<form onSubmit={onFormSubmit}> | |||
<header className="modal-head"> | |||
<h2>{header}</h2> | |||
</header> | |||
<div className="modal-body"> | |||
{translateWithParameters( | |||
'custom_measures.delete_custom_measure.confirmation', | |||
measure.metric.name | |||
)} | |||
</div> | |||
<footer className="modal-foot"> | |||
<DeferredSpinner className="spacer-right" loading={submitting} /> | |||
<SubmitButton className="button-red" disabled={submitting}> | |||
{translate('delete')} | |||
</SubmitButton> | |||
<ResetButtonLink disabled={submitting} onClick={onCloseClick}> | |||
{translate('cancel')} | |||
</ResetButtonLink> | |||
</footer> | |||
</form> | |||
)} | |||
</SimpleModal> | |||
); | |||
} |
@@ -1,208 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons'; | |||
import Select from 'sonar-ui-common/components/controls/Select'; | |||
import SimpleModal from 'sonar-ui-common/components/controls/SimpleModal'; | |||
import { Alert } from 'sonar-ui-common/components/ui/Alert'; | |||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||
import MandatoryFieldMarker from 'sonar-ui-common/components/ui/MandatoryFieldMarker'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { getAllMetrics } from '../../../api/metrics'; | |||
interface Props { | |||
confirmButtonText: string; | |||
header: string; | |||
measure?: T.CustomMeasure; | |||
onClose: () => void; | |||
onSubmit: (data: { description: string; metricKey: string; value: string }) => Promise<void>; | |||
skipMetrics?: string[]; | |||
} | |||
interface State { | |||
description: string; | |||
loading: boolean; | |||
metricKey?: string; | |||
metrics?: T.Metric[]; | |||
value: string; | |||
} | |||
export default class Form extends React.PureComponent<Props, State> { | |||
mounted = false; | |||
constructor(props: Props) { | |||
super(props); | |||
this.state = { | |||
description: (props.measure && props.measure.description) || '', | |||
loading: false, | |||
metricKey: props.measure && props.measure.metric.key, | |||
value: (props.measure && props.measure.value) || '' | |||
}; | |||
} | |||
componentDidMount() { | |||
this.mounted = true; | |||
if (!this.props.measure) { | |||
this.fetchCustomMetrics(); | |||
} | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
handleSubmit = () => { | |||
return this.state.metricKey | |||
? this.props | |||
.onSubmit({ | |||
description: this.state.description, | |||
metricKey: this.state.metricKey, | |||
value: this.state.value | |||
}) | |||
.then(this.props.onClose) | |||
: Promise.reject(undefined); | |||
}; | |||
fetchCustomMetrics = () => { | |||
this.setState({ loading: true }); | |||
getAllMetrics({ isCustom: true }).then( | |||
metrics => { | |||
if (this.mounted) { | |||
this.setState({ loading: false, metrics }); | |||
} | |||
}, | |||
() => { | |||
if (this.mounted) { | |||
this.setState({ loading: false }); | |||
} | |||
} | |||
); | |||
}; | |||
handleMetricSelect = ({ value }: { value: string }) => { | |||
this.setState({ metricKey: value }); | |||
}; | |||
handleDescriptionChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => { | |||
this.setState({ description: event.currentTarget.value }); | |||
}; | |||
handleValueChange = (event: React.ChangeEvent<HTMLInputElement>) => { | |||
this.setState({ value: event.currentTarget.value }); | |||
}; | |||
renderMetricSelect = (options: { label: string; value: string }[]) => { | |||
if (!options.length && !this.state.loading) { | |||
return <Alert variant="warning">{translate('custom_measures.all_metrics_taken')}</Alert>; | |||
} | |||
return ( | |||
<div className="modal-field"> | |||
<label htmlFor="create-custom-measure-metric"> | |||
{translate('custom_measures.metric')} | |||
<MandatoryFieldMarker /> | |||
</label> | |||
{this.state.loading ? ( | |||
<i className="spinner" /> | |||
) : ( | |||
<Select | |||
autoFocus={true} | |||
clearable={false} | |||
id="create-custom-measure-metric" | |||
onChange={this.handleMetricSelect} | |||
options={options} | |||
value={this.state.metricKey} | |||
/> | |||
)} | |||
</div> | |||
); | |||
}; | |||
render() { | |||
const { skipMetrics = [] } = this.props; | |||
const { metrics = [] } = this.state; | |||
const options = metrics | |||
.filter(metric => !skipMetrics.includes(metric.key)) | |||
.map(metric => ({ label: metric.name, value: metric.key })); | |||
const forbidSubmitting = !this.props.measure && !options.length; | |||
return ( | |||
<SimpleModal | |||
header={this.props.header} | |||
onClose={this.props.onClose} | |||
onSubmit={this.handleSubmit} | |||
size="small"> | |||
{({ onCloseClick, onFormSubmit, submitting }) => ( | |||
<form onSubmit={onFormSubmit}> | |||
<header className="modal-head"> | |||
<h2>{this.props.header}</h2> | |||
</header> | |||
<div className="modal-body"> | |||
{!this.props.measure && this.renderMetricSelect(options)} | |||
<div className="modal-field"> | |||
<label htmlFor="create-custom-measure-value"> | |||
{translate('value')} | |||
<MandatoryFieldMarker /> | |||
</label> | |||
<input | |||
autoFocus={this.props.measure !== undefined} | |||
id="create-custom-measure-value" | |||
maxLength={200} | |||
name="value" | |||
onChange={this.handleValueChange} | |||
required={true} | |||
type="text" | |||
value={this.state.value} | |||
/> | |||
</div> | |||
<div className="modal-field"> | |||
<label htmlFor="create-custom-measure-description"> | |||
{translate('description')} | |||
</label> | |||
<textarea | |||
id="create-custom-measure-description" | |||
name="description" | |||
onChange={this.handleDescriptionChange} | |||
value={this.state.description} | |||
/> | |||
</div> | |||
</div> | |||
<footer className="modal-foot"> | |||
<DeferredSpinner className="spacer-right" loading={submitting} /> | |||
<SubmitButton | |||
disabled={forbidSubmitting || submitting} | |||
id="create-custom-measure-submit"> | |||
{this.props.confirmButtonText} | |||
</SubmitButton> | |||
<ResetButtonLink | |||
disabled={submitting} | |||
id="create-custom-measure-cancel" | |||
onClick={onCloseClick}> | |||
{translate('cancel')} | |||
</ResetButtonLink> | |||
</footer> | |||
</form> | |||
)} | |||
</SimpleModal> | |||
); | |||
} | |||
} |
@@ -1,48 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { Alert } from 'sonar-ui-common/components/ui/Alert'; | |||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import CreateButton from './CreateButton'; | |||
interface Props { | |||
loading: boolean; | |||
onCreate: (data: { description: string; metricKey: string; value: string }) => Promise<void>; | |||
skipMetrics: string[] | undefined; | |||
} | |||
export default function Header({ loading, onCreate, skipMetrics }: Props) { | |||
return ( | |||
<header className="page-header" id="custom-measures-header"> | |||
<h1 className="page-title">{translate('custom_measures.page')}</h1> | |||
<DeferredSpinner loading={loading} /> | |||
<div className="page-actions"> | |||
<CreateButton onCreate={onCreate} skipMetrics={skipMetrics} /> | |||
</div> | |||
<div className="page-description"> | |||
<Alert display="inline" variant="error"> | |||
{translate('custom_measures.deprecated')} | |||
</Alert> | |||
<p>{translate('custom_measures.page.description')}</p> | |||
</div> | |||
</header> | |||
); | |||
} |
@@ -1,163 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import ActionsDropdown, { | |||
ActionsDropdownDivider, | |||
ActionsDropdownItem | |||
} from 'sonar-ui-common/components/controls/ActionsDropdown'; | |||
import Tooltip from 'sonar-ui-common/components/controls/Tooltip'; | |||
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n'; | |||
import { formatMeasure } from 'sonar-ui-common/helpers/measures'; | |||
import { isUserActive } from '../../../helpers/users'; | |||
import DeleteForm from './DeleteForm'; | |||
import Form from './Form'; | |||
import MeasureDate from './MeasureDate'; | |||
interface Props { | |||
measure: T.CustomMeasure; | |||
onDelete: (measureId: string) => Promise<void>; | |||
onEdit: (data: { description: string; id: string; value: string }) => Promise<void>; | |||
} | |||
interface State { | |||
deleteForm: boolean; | |||
editForm: boolean; | |||
} | |||
export default class Item extends React.PureComponent<Props, State> { | |||
mounted = false; | |||
state: State = { | |||
deleteForm: false, | |||
editForm: false | |||
}; | |||
componentDidMount() { | |||
this.mounted = true; | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
handleEditClick = () => { | |||
this.setState({ editForm: true }); | |||
}; | |||
handleDeleteClick = () => { | |||
this.setState({ deleteForm: true }); | |||
}; | |||
closeEditForm = () => { | |||
if (this.mounted) { | |||
this.setState({ editForm: false }); | |||
} | |||
}; | |||
closeDeleteForm = () => { | |||
if (this.mounted) { | |||
this.setState({ deleteForm: false }); | |||
} | |||
}; | |||
handleEditFormSubmit = (data: { description: string; value: string }) => { | |||
return this.props.onEdit({ id: this.props.measure.id, ...data }); | |||
}; | |||
handleDeleteFormSubmit = () => { | |||
return this.props.onDelete(this.props.measure.id); | |||
}; | |||
render() { | |||
const { measure } = this.props; | |||
const userName = measure.user.name || measure.user.login; | |||
return ( | |||
<tr data-metric={measure.metric.key}> | |||
<td className="nowrap"> | |||
<div> | |||
<span className="js-custom-measure-metric-name">{measure.metric.name}</span> | |||
{measure.pending && ( | |||
<Tooltip overlay={translate('custom_measures.pending_tooltip')}> | |||
<span className="js-custom-measure-pending badge badge-warning spacer-left"> | |||
{translate('custom_measures.pending')} | |||
</span> | |||
</Tooltip> | |||
)} | |||
</div> | |||
<span className="js-custom-measure-domain note">{measure.metric.domain}</span> | |||
</td> | |||
<td className="nowrap"> | |||
<strong className="js-custom-measure-value"> | |||
{formatMeasure(measure.value, measure.metric.type)} | |||
</strong> | |||
</td> | |||
<td> | |||
<span className="js-custom-measure-description">{measure.description}</span> | |||
</td> | |||
<td> | |||
<MeasureDate measure={measure} /> {translate('by_')}{' '} | |||
<span className="js-custom-measure-user"> | |||
{isUserActive(measure.user) | |||
? userName | |||
: translateWithParameters('user.x_deleted', userName)} | |||
</span> | |||
</td> | |||
<td className="thin nowrap"> | |||
<ActionsDropdown> | |||
<ActionsDropdownItem | |||
className="js-custom-measure-update" | |||
onClick={this.handleEditClick}> | |||
{translate('update_verb')} | |||
</ActionsDropdownItem> | |||
<ActionsDropdownDivider /> | |||
<ActionsDropdownItem | |||
className="js-custom-measure-delete" | |||
destructive={true} | |||
onClick={this.handleDeleteClick}> | |||
{translate('delete')} | |||
</ActionsDropdownItem> | |||
</ActionsDropdown> | |||
</td> | |||
{this.state.editForm && ( | |||
<Form | |||
confirmButtonText={translate('update_verb')} | |||
header={translate('custom_measures.update_custom_measure')} | |||
measure={this.props.measure} | |||
onClose={this.closeEditForm} | |||
onSubmit={this.handleEditFormSubmit} | |||
/> | |||
)} | |||
{this.state.deleteForm && ( | |||
<DeleteForm | |||
measure={this.props.measure} | |||
onClose={this.closeDeleteForm} | |||
onSubmit={this.handleDeleteFormSubmit} | |||
/> | |||
)} | |||
</tr> | |||
); | |||
} | |||
} |
@@ -1,56 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { sortBy } from 'lodash'; | |||
import * as React from 'react'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import Item from './Item'; | |||
interface Props { | |||
measures: T.CustomMeasure[]; | |||
onDelete: (measureId: string) => Promise<void>; | |||
onEdit: (data: { description: string; id: string; value: string }) => Promise<void>; | |||
} | |||
export default function List({ measures, onDelete, onEdit }: Props) { | |||
return ( | |||
<div className="boxed-group boxed-group-inner" id="custom-measures-list"> | |||
{measures.length > 0 ? ( | |||
<table className="data zebra zebra-hover"> | |||
<thead> | |||
<tr> | |||
<th>{translate('custom_measures.metric')}</th> | |||
<th>{translate('value')}</th> | |||
<th>{translate('description')}</th> | |||
<th>{translate('date')}</th> | |||
<th /> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{sortBy(measures, measure => measure.metric.name.toLowerCase()).map(measure => ( | |||
<Item key={measure.id} measure={measure} onDelete={onDelete} onEdit={onEdit} /> | |||
))} | |||
</tbody> | |||
</table> | |||
) : ( | |||
<p>{translate('no_results')}</p> | |||
)} | |||
</div> | |||
); | |||
} |
@@ -1,50 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import DateFormatter from 'sonar-ui-common/components/intl/DateFormatter'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
interface Props { | |||
measure: T.CustomMeasure; | |||
} | |||
export default function MeasureDate({ measure }: Props) { | |||
if (measure.updatedAt) { | |||
return ( | |||
<> | |||
{translate('updated_on')}{' '} | |||
<span className="js-custom-measure-created-at"> | |||
<DateFormatter date={measure.updatedAt} /> | |||
</span> | |||
</> | |||
); | |||
} else if (measure.createdAt) { | |||
return ( | |||
<> | |||
{translate('created_on')}{' '} | |||
<span className="js-custom-measure-created-at"> | |||
<DateFormatter date={measure.createdAt} /> | |||
</span> | |||
</> | |||
); | |||
} else { | |||
return <>{translate('created')}</>; | |||
} | |||
} |
@@ -1,87 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | |||
import App from '../App'; | |||
jest.mock('../../../../api/measures', () => ({ | |||
getCustomMeasures: () => | |||
Promise.resolve({ | |||
customMeasures: [ | |||
{ | |||
createdAt: '2017-01-01', | |||
description: 'my custom measure', | |||
id: '1', | |||
metric: { key: 'custom', name: 'custom-metric', type: 'STRING' }, | |||
projectKey: 'foo', | |||
user: { active: true, login: 'user', name: 'user' }, | |||
value: 'custom-value' | |||
} | |||
], | |||
paging: { pageIndex: 1, pageSize: 1, total: 1 } | |||
}), | |||
createCustomMeasure: () => | |||
Promise.resolve({ | |||
createdAt: '2018-01-01', | |||
description: 'description', | |||
id: '2', | |||
metric: { key: 'metricKey', name: 'Metric Name', type: 'STRING' }, | |||
projectKey: 'foo', | |||
user: { active: true, login: 'user', name: 'user' }, | |||
value: 'value' | |||
}), | |||
updateCustomMeasure: () => Promise.resolve(), | |||
deleteCustomMeasure: () => Promise.resolve() | |||
})); | |||
it('should work', async () => { | |||
const wrapper = shallow<App>(<App component={{ key: 'foo' }} />); | |||
expect(wrapper).toMatchSnapshot(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
// create | |||
wrapper.find('Header').prop<Function>('onCreate')({ | |||
description: 'description', | |||
metricKey: 'metricKey', | |||
value: 'value' | |||
}); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().measures).toMatchSnapshot(); | |||
expect(wrapper.state().paging!.total).toBe(2); | |||
// edit | |||
wrapper.find('List').prop<Function>('onEdit')({ | |||
description: 'another', | |||
id: '2', | |||
value: 'other' | |||
}); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().measures).toMatchSnapshot(); | |||
expect(wrapper.state().paging!.total).toBe(2); | |||
// delete | |||
wrapper.find('List').prop<Function>('onDelete')('2'); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().measures).toMatchSnapshot(); | |||
expect(wrapper.state().paging!.total).toBe(1); | |||
}); |
@@ -1,43 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { click } from 'sonar-ui-common/helpers/testUtils'; | |||
import CreateButton from '../CreateButton'; | |||
it('should create new custom measure', () => { | |||
const onCreate = jest.fn(() => Promise.resolve()); | |||
const wrapper = shallow(<CreateButton onCreate={onCreate} skipMetrics={[]} />); | |||
expect(wrapper).toMatchSnapshot(); | |||
click(wrapper.find('#custom-measures-create')); | |||
expect(wrapper).toMatchSnapshot(); | |||
wrapper.find('Form').prop<Function>('onSubmit')({ | |||
description: 'description', | |||
metricKey: 'metricKey', | |||
value: 'value' | |||
}); | |||
expect(onCreate).toBeCalledWith({ | |||
description: 'description', | |||
metricKey: 'metricKey', | |||
value: 'value' | |||
}); | |||
}); |
@@ -1,37 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import DeleteForm from '../DeleteForm'; | |||
it('should render', () => { | |||
const measure = { | |||
createdAt: '2017-01-01', | |||
description: 'my custom measure', | |||
id: '1', | |||
metric: { key: 'custom', name: 'custom-metric', type: 'STRING' }, | |||
projectKey: 'foo', | |||
user: { active: true, login: 'user', name: 'user' }, | |||
value: 'custom-value' | |||
}; | |||
expect( | |||
shallow(<DeleteForm measure={measure} onClose={jest.fn()} onSubmit={jest.fn()} />).dive() | |||
).toMatchSnapshot(); | |||
}); |
@@ -1,67 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { change, click, submit, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | |||
import Form from '../Form'; | |||
jest.mock('../../../../api/metrics', () => ({ | |||
getAllMetrics: () => | |||
Promise.resolve([ | |||
{ id: '1', key: 'custom-metric', name: 'Custom Metric', type: 'STRING' }, | |||
{ id: '2', key: 'skipped-metric', name: 'Skipped Metric', type: 'FLOAT' } | |||
]) | |||
})); | |||
it('should render form', async () => { | |||
const onClose = jest.fn(); | |||
const onSubmit = jest.fn(() => Promise.resolve()); | |||
const wrapper = shallow( | |||
<Form | |||
confirmButtonText="confirmButtonText" | |||
header="header" | |||
onClose={onClose} | |||
onSubmit={onSubmit} | |||
skipMetrics={['skipped-metric']} | |||
/> | |||
); | |||
expect(wrapper.dive()).toMatchSnapshot(); | |||
await waitAndUpdate(wrapper); | |||
const form = wrapper.dive(); | |||
expect(form).toMatchSnapshot(); | |||
form.find('Select').prop<Function>('onChange')({ value: 'custom-metric' }); | |||
change(form.find('[name="value"]'), 'Foo'); | |||
change(form.find('[name="description"]'), 'bar'); | |||
submit(form.find('form')); | |||
expect(onSubmit).toBeCalledWith({ | |||
description: 'bar', | |||
metricKey: 'custom-metric', | |||
value: 'Foo' | |||
}); | |||
await new Promise(setImmediate); | |||
expect(onClose).toBeCalled(); | |||
onClose.mockClear(); | |||
click(form.find('ResetButtonLink')); | |||
expect(onClose).toBeCalled(); | |||
}); |
@@ -1,35 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import Header from '../Header'; | |||
it('should create new custom measure', () => { | |||
const onCreate = jest.fn(() => Promise.resolve()); | |||
const wrapper = shallow(<Header loading={false} onCreate={onCreate} skipMetrics={[]} />); | |||
expect(wrapper).toMatchSnapshot(); | |||
wrapper.find('CreateButton').prop<Function>('onCreate')({ | |||
description: 'bla', | |||
metricKey: 'custom-metric', | |||
name: 'Foo' | |||
}); | |||
expect(onCreate).toBeCalledWith({ description: 'bla', metricKey: 'custom-metric', name: 'Foo' }); | |||
}); |
@@ -1,73 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { click } from 'sonar-ui-common/helpers/testUtils'; | |||
import Item from '../Item'; | |||
const measure = { | |||
createdAt: '2017-01-01', | |||
description: 'my custom measure', | |||
id: '1', | |||
metric: { key: 'custom', name: 'custom-metric', type: 'STRING' }, | |||
projectKey: 'foo', | |||
user: { active: true, login: 'user', name: 'user' }, | |||
value: 'custom-value' | |||
}; | |||
it('should render', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
it('should edit metric', () => { | |||
const onEdit = jest.fn(); | |||
const wrapper = shallowRender({ onEdit }); | |||
click(wrapper.find('.js-custom-measure-update')); | |||
wrapper.update(); | |||
wrapper.find('Form').prop<Function>('onSubmit')({ | |||
...measure, | |||
description: 'new-description', | |||
value: 'new-value' | |||
}); | |||
expect(onEdit).toBeCalledWith({ ...measure, description: 'new-description', value: 'new-value' }); | |||
}); | |||
it('should delete custom measure', () => { | |||
const onDelete = jest.fn(); | |||
const wrapper = shallowRender({ onDelete }); | |||
click(wrapper.find('.js-custom-measure-delete')); | |||
wrapper.update(); | |||
wrapper.find('DeleteForm').prop<Function>('onSubmit')(); | |||
expect(onDelete).toBeCalledWith('1'); | |||
}); | |||
it('should render correctly for deleted user', () => { | |||
expect( | |||
shallowRender({ measure: { ...measure, user: { active: false, login: 'user' } } }) | |||
).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<Item['props']> = {}) { | |||
return shallow(<Item measure={measure} onDelete={jest.fn()} onEdit={jest.fn()} {...props} />); | |||
} |
@@ -1,51 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import List from '../List'; | |||
it('should render', () => { | |||
const measures = [ | |||
{ | |||
createdAt: '2017-01-01', | |||
description: 'my custom measure', | |||
id: '1', | |||
metric: { key: 'custom', name: 'custom-metric', type: 'STRING' }, | |||
projectKey: 'foo', | |||
user: { active: true, login: 'user', name: 'user' }, | |||
value: 'custom-value' | |||
}, | |||
{ | |||
createdAt: '2017-01-01', | |||
id: '2', | |||
metric: { key: 'another', name: 'another-metric', type: 'STRING' }, | |||
projectKey: 'foo', | |||
user: { active: true, login: 'user', name: 'user' }, | |||
value: 'another-value' | |||
} | |||
]; | |||
expect( | |||
shallow(<List measures={measures} onDelete={jest.fn()} onEdit={jest.fn()} />) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render no results', () => { | |||
expect(shallow(<List measures={[]} onDelete={jest.fn()} onEdit={jest.fn()} />)).toMatchSnapshot(); | |||
}); |
@@ -1,179 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should work 1`] = ` | |||
<Fragment> | |||
<Suggestions | |||
suggestions="custom_measures" | |||
/> | |||
<Helmet | |||
defer={true} | |||
encodeSpecialCharacters={true} | |||
title="custom_measures.page" | |||
/> | |||
<div | |||
className="page page-limited" | |||
> | |||
<Header | |||
loading={true} | |||
onCreate={[Function]} | |||
/> | |||
</div> | |||
</Fragment> | |||
`; | |||
exports[`should work 2`] = ` | |||
<Fragment> | |||
<Suggestions | |||
suggestions="custom_measures" | |||
/> | |||
<Helmet | |||
defer={true} | |||
encodeSpecialCharacters={true} | |||
title="custom_measures.page" | |||
/> | |||
<div | |||
className="page page-limited" | |||
> | |||
<Header | |||
loading={false} | |||
onCreate={[Function]} | |||
skipMetrics={ | |||
Array [ | |||
"custom", | |||
] | |||
} | |||
/> | |||
<List | |||
measures={ | |||
Array [ | |||
Object { | |||
"createdAt": "2017-01-01", | |||
"description": "my custom measure", | |||
"id": "1", | |||
"metric": Object { | |||
"key": "custom", | |||
"name": "custom-metric", | |||
"type": "STRING", | |||
}, | |||
"projectKey": "foo", | |||
"user": Object { | |||
"active": true, | |||
"login": "user", | |||
"name": "user", | |||
}, | |||
"value": "custom-value", | |||
}, | |||
] | |||
} | |||
onDelete={[Function]} | |||
onEdit={[Function]} | |||
/> | |||
<ListFooter | |||
count={1} | |||
loadMore={[Function]} | |||
ready={true} | |||
total={1} | |||
/> | |||
</div> | |||
</Fragment> | |||
`; | |||
exports[`should work 3`] = ` | |||
Array [ | |||
Object { | |||
"createdAt": "2017-01-01", | |||
"description": "my custom measure", | |||
"id": "1", | |||
"metric": Object { | |||
"key": "custom", | |||
"name": "custom-metric", | |||
"type": "STRING", | |||
}, | |||
"projectKey": "foo", | |||
"user": Object { | |||
"active": true, | |||
"login": "user", | |||
"name": "user", | |||
}, | |||
"value": "custom-value", | |||
}, | |||
Object { | |||
"createdAt": "2018-01-01", | |||
"description": "description", | |||
"id": "2", | |||
"metric": Object { | |||
"key": "metricKey", | |||
"name": "Metric Name", | |||
"type": "STRING", | |||
}, | |||
"projectKey": "foo", | |||
"user": Object { | |||
"active": true, | |||
"login": "user", | |||
"name": "user", | |||
}, | |||
"value": "value", | |||
}, | |||
] | |||
`; | |||
exports[`should work 4`] = ` | |||
Array [ | |||
Object { | |||
"createdAt": "2017-01-01", | |||
"description": "my custom measure", | |||
"id": "1", | |||
"metric": Object { | |||
"key": "custom", | |||
"name": "custom-metric", | |||
"type": "STRING", | |||
}, | |||
"projectKey": "foo", | |||
"user": Object { | |||
"active": true, | |||
"login": "user", | |||
"name": "user", | |||
}, | |||
"value": "custom-value", | |||
}, | |||
Object { | |||
"createdAt": "2018-01-01", | |||
"description": "another", | |||
"id": "2", | |||
"metric": Object { | |||
"key": "metricKey", | |||
"name": "Metric Name", | |||
"type": "STRING", | |||
}, | |||
"projectKey": "foo", | |||
"user": Object { | |||
"active": true, | |||
"login": "user", | |||
"name": "user", | |||
}, | |||
"value": "other", | |||
}, | |||
] | |||
`; | |||
exports[`should work 5`] = ` | |||
Array [ | |||
Object { | |||
"createdAt": "2017-01-01", | |||
"description": "my custom measure", | |||
"id": "1", | |||
"metric": Object { | |||
"key": "custom", | |||
"name": "custom-metric", | |||
"type": "STRING", | |||
}, | |||
"projectKey": "foo", | |||
"user": Object { | |||
"active": true, | |||
"login": "user", | |||
"name": "user", | |||
}, | |||
"value": "custom-value", | |||
}, | |||
] | |||
`; |
@@ -1,30 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should create new custom measure 1`] = ` | |||
<Fragment> | |||
<Button | |||
id="custom-measures-create" | |||
onClick={[Function]} | |||
> | |||
create | |||
</Button> | |||
</Fragment> | |||
`; | |||
exports[`should create new custom measure 2`] = ` | |||
<Fragment> | |||
<Button | |||
id="custom-measures-create" | |||
onClick={[Function]} | |||
> | |||
create | |||
</Button> | |||
<Form | |||
confirmButtonText="create" | |||
header="custom_measures.create_custom_measure" | |||
onClose={[Function]} | |||
onSubmit={[MockFunction]} | |||
skipMetrics={Array []} | |||
/> | |||
</Fragment> | |||
`; |
@@ -1,45 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render 1`] = ` | |||
<Modal | |||
contentLabel="custom_measures.delete_custom_measure" | |||
onRequestClose={[MockFunction]} | |||
> | |||
<form | |||
onSubmit={[Function]} | |||
> | |||
<header | |||
className="modal-head" | |||
> | |||
<h2> | |||
custom_measures.delete_custom_measure | |||
</h2> | |||
</header> | |||
<div | |||
className="modal-body" | |||
> | |||
custom_measures.delete_custom_measure.confirmation.custom-metric | |||
</div> | |||
<footer | |||
className="modal-foot" | |||
> | |||
<DeferredSpinner | |||
className="spacer-right" | |||
loading={false} | |||
/> | |||
<SubmitButton | |||
className="button-red" | |||
disabled={false} | |||
> | |||
delete | |||
</SubmitButton> | |||
<ResetButtonLink | |||
disabled={false} | |||
onClick={[Function]} | |||
> | |||
cancel | |||
</ResetButtonLink> | |||
</footer> | |||
</form> | |||
</Modal> | |||
`; |
@@ -1,198 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render form 1`] = ` | |||
<Modal | |||
contentLabel="header" | |||
onRequestClose={[MockFunction]} | |||
size="small" | |||
> | |||
<form | |||
onSubmit={[Function]} | |||
> | |||
<header | |||
className="modal-head" | |||
> | |||
<h2> | |||
header | |||
</h2> | |||
</header> | |||
<div | |||
className="modal-body" | |||
> | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
htmlFor="create-custom-measure-metric" | |||
> | |||
custom_measures.metric | |||
<MandatoryFieldMarker /> | |||
</label> | |||
<i | |||
className="spinner" | |||
/> | |||
</div> | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
htmlFor="create-custom-measure-value" | |||
> | |||
value | |||
<MandatoryFieldMarker /> | |||
</label> | |||
<input | |||
autoFocus={false} | |||
id="create-custom-measure-value" | |||
maxLength={200} | |||
name="value" | |||
onChange={[Function]} | |||
required={true} | |||
type="text" | |||
value="" | |||
/> | |||
</div> | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
htmlFor="create-custom-measure-description" | |||
> | |||
description | |||
</label> | |||
<textarea | |||
id="create-custom-measure-description" | |||
name="description" | |||
onChange={[Function]} | |||
value="" | |||
/> | |||
</div> | |||
</div> | |||
<footer | |||
className="modal-foot" | |||
> | |||
<DeferredSpinner | |||
className="spacer-right" | |||
loading={false} | |||
/> | |||
<SubmitButton | |||
disabled={true} | |||
id="create-custom-measure-submit" | |||
> | |||
confirmButtonText | |||
</SubmitButton> | |||
<ResetButtonLink | |||
disabled={false} | |||
id="create-custom-measure-cancel" | |||
onClick={[Function]} | |||
> | |||
cancel | |||
</ResetButtonLink> | |||
</footer> | |||
</form> | |||
</Modal> | |||
`; | |||
exports[`should render form 2`] = ` | |||
<Modal | |||
contentLabel="header" | |||
onRequestClose={[MockFunction]} | |||
size="small" | |||
> | |||
<form | |||
onSubmit={[Function]} | |||
> | |||
<header | |||
className="modal-head" | |||
> | |||
<h2> | |||
header | |||
</h2> | |||
</header> | |||
<div | |||
className="modal-body" | |||
> | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
htmlFor="create-custom-measure-metric" | |||
> | |||
custom_measures.metric | |||
<MandatoryFieldMarker /> | |||
</label> | |||
<Select | |||
autoFocus={true} | |||
clearable={false} | |||
id="create-custom-measure-metric" | |||
onChange={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "Custom Metric", | |||
"value": "custom-metric", | |||
}, | |||
] | |||
} | |||
/> | |||
</div> | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
htmlFor="create-custom-measure-value" | |||
> | |||
value | |||
<MandatoryFieldMarker /> | |||
</label> | |||
<input | |||
autoFocus={false} | |||
id="create-custom-measure-value" | |||
maxLength={200} | |||
name="value" | |||
onChange={[Function]} | |||
required={true} | |||
type="text" | |||
value="" | |||
/> | |||
</div> | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
htmlFor="create-custom-measure-description" | |||
> | |||
description | |||
</label> | |||
<textarea | |||
id="create-custom-measure-description" | |||
name="description" | |||
onChange={[Function]} | |||
value="" | |||
/> | |||
</div> | |||
</div> | |||
<footer | |||
className="modal-foot" | |||
> | |||
<DeferredSpinner | |||
className="spacer-right" | |||
loading={false} | |||
/> | |||
<SubmitButton | |||
disabled={false} | |||
id="create-custom-measure-submit" | |||
> | |||
confirmButtonText | |||
</SubmitButton> | |||
<ResetButtonLink | |||
disabled={false} | |||
id="create-custom-measure-cancel" | |||
onClick={[Function]} | |||
> | |||
cancel | |||
</ResetButtonLink> | |||
</footer> | |||
</form> | |||
</Modal> | |||
`; |
@@ -1,38 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should create new custom measure 1`] = ` | |||
<header | |||
className="page-header" | |||
id="custom-measures-header" | |||
> | |||
<h1 | |||
className="page-title" | |||
> | |||
custom_measures.page | |||
</h1> | |||
<DeferredSpinner | |||
loading={false} | |||
/> | |||
<div | |||
className="page-actions" | |||
> | |||
<CreateButton | |||
onCreate={[MockFunction]} | |||
skipMetrics={Array []} | |||
/> | |||
</div> | |||
<div | |||
className="page-description" | |||
> | |||
<Alert | |||
display="inline" | |||
variant="error" | |||
> | |||
custom_measures.deprecated | |||
</Alert> | |||
<p> | |||
custom_measures.page.description | |||
</p> | |||
</div> | |||
</header> | |||
`; |
@@ -1,176 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render 1`] = ` | |||
<tr | |||
data-metric="custom" | |||
> | |||
<td | |||
className="nowrap" | |||
> | |||
<div> | |||
<span | |||
className="js-custom-measure-metric-name" | |||
> | |||
custom-metric | |||
</span> | |||
</div> | |||
<span | |||
className="js-custom-measure-domain note" | |||
/> | |||
</td> | |||
<td | |||
className="nowrap" | |||
> | |||
<strong | |||
className="js-custom-measure-value" | |||
> | |||
custom-value | |||
</strong> | |||
</td> | |||
<td> | |||
<span | |||
className="js-custom-measure-description" | |||
> | |||
my custom measure | |||
</span> | |||
</td> | |||
<td> | |||
<MeasureDate | |||
measure={ | |||
Object { | |||
"createdAt": "2017-01-01", | |||
"description": "my custom measure", | |||
"id": "1", | |||
"metric": Object { | |||
"key": "custom", | |||
"name": "custom-metric", | |||
"type": "STRING", | |||
}, | |||
"projectKey": "foo", | |||
"user": Object { | |||
"active": true, | |||
"login": "user", | |||
"name": "user", | |||
}, | |||
"value": "custom-value", | |||
} | |||
} | |||
/> | |||
by_ | |||
<span | |||
className="js-custom-measure-user" | |||
> | |||
user | |||
</span> | |||
</td> | |||
<td | |||
className="thin nowrap" | |||
> | |||
<ActionsDropdown> | |||
<ActionsDropdownItem | |||
className="js-custom-measure-update" | |||
onClick={[Function]} | |||
> | |||
update_verb | |||
</ActionsDropdownItem> | |||
<ActionsDropdownDivider /> | |||
<ActionsDropdownItem | |||
className="js-custom-measure-delete" | |||
destructive={true} | |||
onClick={[Function]} | |||
> | |||
delete | |||
</ActionsDropdownItem> | |||
</ActionsDropdown> | |||
</td> | |||
</tr> | |||
`; | |||
exports[`should render correctly for deleted user 1`] = ` | |||
<tr | |||
data-metric="custom" | |||
> | |||
<td | |||
className="nowrap" | |||
> | |||
<div> | |||
<span | |||
className="js-custom-measure-metric-name" | |||
> | |||
custom-metric | |||
</span> | |||
</div> | |||
<span | |||
className="js-custom-measure-domain note" | |||
/> | |||
</td> | |||
<td | |||
className="nowrap" | |||
> | |||
<strong | |||
className="js-custom-measure-value" | |||
> | |||
custom-value | |||
</strong> | |||
</td> | |||
<td> | |||
<span | |||
className="js-custom-measure-description" | |||
> | |||
my custom measure | |||
</span> | |||
</td> | |||
<td> | |||
<MeasureDate | |||
measure={ | |||
Object { | |||
"createdAt": "2017-01-01", | |||
"description": "my custom measure", | |||
"id": "1", | |||
"metric": Object { | |||
"key": "custom", | |||
"name": "custom-metric", | |||
"type": "STRING", | |||
}, | |||
"projectKey": "foo", | |||
"user": Object { | |||
"active": false, | |||
"login": "user", | |||
}, | |||
"value": "custom-value", | |||
} | |||
} | |||
/> | |||
by_ | |||
<span | |||
className="js-custom-measure-user" | |||
> | |||
user.x_deleted.user | |||
</span> | |||
</td> | |||
<td | |||
className="thin nowrap" | |||
> | |||
<ActionsDropdown> | |||
<ActionsDropdownItem | |||
className="js-custom-measure-update" | |||
onClick={[Function]} | |||
> | |||
update_verb | |||
</ActionsDropdownItem> | |||
<ActionsDropdownDivider /> | |||
<ActionsDropdownItem | |||
className="js-custom-measure-delete" | |||
destructive={true} | |||
onClick={[Function]} | |||
> | |||
delete | |||
</ActionsDropdownItem> | |||
</ActionsDropdown> | |||
</td> | |||
</tr> | |||
`; |
@@ -1,90 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render 1`] = ` | |||
<div | |||
className="boxed-group boxed-group-inner" | |||
id="custom-measures-list" | |||
> | |||
<table | |||
className="data zebra zebra-hover" | |||
> | |||
<thead> | |||
<tr> | |||
<th> | |||
custom_measures.metric | |||
</th> | |||
<th> | |||
value | |||
</th> | |||
<th> | |||
description | |||
</th> | |||
<th> | |||
date | |||
</th> | |||
<th /> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<Item | |||
key="2" | |||
measure={ | |||
Object { | |||
"createdAt": "2017-01-01", | |||
"id": "2", | |||
"metric": Object { | |||
"key": "another", | |||
"name": "another-metric", | |||
"type": "STRING", | |||
}, | |||
"projectKey": "foo", | |||
"user": Object { | |||
"active": true, | |||
"login": "user", | |||
"name": "user", | |||
}, | |||
"value": "another-value", | |||
} | |||
} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
<Item | |||
key="1" | |||
measure={ | |||
Object { | |||
"createdAt": "2017-01-01", | |||
"description": "my custom measure", | |||
"id": "1", | |||
"metric": Object { | |||
"key": "custom", | |||
"name": "custom-metric", | |||
"type": "STRING", | |||
}, | |||
"projectKey": "foo", | |||
"user": Object { | |||
"active": true, | |||
"login": "user", | |||
"name": "user", | |||
}, | |||
"value": "custom-value", | |||
} | |||
} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
</tbody> | |||
</table> | |||
</div> | |||
`; | |||
exports[`should render no results 1`] = ` | |||
<div | |||
className="boxed-group boxed-group-inner" | |||
id="custom-measures-list" | |||
> | |||
<p> | |||
no_results | |||
</p> | |||
</div> | |||
`; |
@@ -1,28 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent'; | |||
const routes = [ | |||
{ | |||
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) } | |||
} | |||
]; | |||
export default routes; |
@@ -136,7 +136,6 @@ declare namespace T { | |||
showBackgroundTasks?: boolean; | |||
showHistory?: boolean; | |||
showLinks?: boolean; | |||
showManualMeasures?: boolean; | |||
showQualityGates?: boolean; | |||
showQualityProfiles?: boolean; | |||
showPermissions?: boolean; |
@@ -1,28 +0,0 @@ | |||
{ | |||
"metrics": [ | |||
{ | |||
"id": "AU-Tpxb--iU5OvuD2FLy", | |||
"key": "team_size", | |||
"name": "Team size", | |||
"description": "Number of people in the team", | |||
"domain": "Management", | |||
"type": "INT", | |||
"direction": 0, | |||
"qualitative": false, | |||
"hidden": false, | |||
"custom": true | |||
}, | |||
{ | |||
"id": "AU-Tpxb--iU5OvuD3FLz", | |||
"key": "uncovered_lines", | |||
"name": "Uncovered lines", | |||
"description": "Uncovered lines", | |||
"domain": "Tests", | |||
"type": "INT", | |||
"direction": 1, | |||
"qualitative": true, | |||
"hidden": false, | |||
"custom": false | |||
} | |||
] | |||
} |
@@ -1,64 +0,0 @@ | |||
{ | |||
"customMeasures": [ | |||
{ | |||
"description": "New arrivals", | |||
"metric": { | |||
"key": "team_size", | |||
"name": "Team Size", | |||
"domain": "Tests", | |||
"type": "INT" | |||
}, | |||
"projectId": "project-uuid", | |||
"projectKey": "project-key", | |||
"pending": true, | |||
"user": { | |||
"active": true, | |||
"email": "login@login.com", | |||
"login": "login", | |||
"name": "Stan Smith" | |||
}, | |||
"value": "42" | |||
}, | |||
{ | |||
"description": "New funds", | |||
"metric": { | |||
"key": "burned_budget", | |||
"name": "Burned Budget", | |||
"domain": "Activity", | |||
"type": "INT" | |||
}, | |||
"projectId": "project-uuid", | |||
"projectKey": "project-key", | |||
"pending": false, | |||
"user": { | |||
"active": true, | |||
"email": "login@login.com", | |||
"login": "login", | |||
"name": "Stan Smith" | |||
}, | |||
"value": "1000000" | |||
}, | |||
{ | |||
"description": "Great coverage", | |||
"metric": { | |||
"key": "uncovered_lines", | |||
"name": "Uncovered lines", | |||
"domain": "Code Coverage", | |||
"type": "INT" | |||
}, | |||
"projectId": "project-uuid", | |||
"projectKey": "project-key", | |||
"pending": false, | |||
"user": { | |||
"active": true, | |||
"email": "login@login.com", | |||
"login": "login", | |||
"name": "Stan Smith" | |||
}, | |||
"value": "1" | |||
} | |||
], | |||
"p": 1, | |||
"ps": 100, | |||
"total": 3 | |||
} |
@@ -1,37 +0,0 @@ | |||
{ | |||
"metrics": [ | |||
{ | |||
"key": "custom-key-1", | |||
"type": "INT", | |||
"name": "custom-name-1", | |||
"description": "custom-description-1", | |||
"domain": "custom-domain-1", | |||
"direction": 1, | |||
"qualitative": false, | |||
"hidden": false, | |||
"custom": true | |||
}, | |||
{ | |||
"key": "custom-key-2", | |||
"type": "INT", | |||
"name": "custom-name-2", | |||
"description": "custom-description-2", | |||
"domain": "custom-domain-2", | |||
"direction": -1, | |||
"qualitative": true, | |||
"hidden": true, | |||
"custom": true | |||
}, | |||
{ | |||
"key": "custom-key-3", | |||
"type": "INT", | |||
"name": "custom-name-3", | |||
"description": "custom-description-3", | |||
"domain": "custom-domain-3", | |||
"direction": 0, | |||
"qualitative": false, | |||
"hidden": false, | |||
"custom": true | |||
} | |||
] | |||
} |
@@ -1,64 +0,0 @@ | |||
{ | |||
"customMeasures": [ | |||
{ | |||
"description": "description-1", | |||
"metric": { | |||
"key": "metric-key-1", | |||
"name": "metric-key-1-name", | |||
"domain": "metric-key-1-domain", | |||
"type": "STRING" | |||
}, | |||
"projectId": "project-uuid", | |||
"projectKey": "project-key", | |||
"pending":true, | |||
"user": { | |||
"active": true, | |||
"email": "login@login.com", | |||
"login": "login", | |||
"name": "Login" | |||
}, | |||
"value": "text-value-1" | |||
}, | |||
{ | |||
"description": "description-2", | |||
"metric": { | |||
"key": "metric-key-2", | |||
"name": "metric-key-2-name", | |||
"domain": "metric-key-2-domain", | |||
"type": "STRING" | |||
}, | |||
"projectId": "project-uuid", | |||
"projectKey": "project-key", | |||
"pending":true, | |||
"user": { | |||
"active": true, | |||
"email": "login@login.com", | |||
"login": "login", | |||
"name": "Login" | |||
}, | |||
"value": "text-value-2" | |||
}, | |||
{ | |||
"description": "description-3", | |||
"metric": { | |||
"key": "metric-key-3", | |||
"name": "metric-key-3-name", | |||
"domain": "metric-key-3-domain", | |||
"type": "STRING" | |||
}, | |||
"projectId": "project-uuid", | |||
"projectKey": "project-key", | |||
"pending":true, | |||
"user": { | |||
"active": true, | |||
"email": "login@login.com", | |||
"login": "login", | |||
"name": "Login" | |||
}, | |||
"value": "text-value-3" | |||
} | |||
], | |||
"p": 1, | |||
"ps": 100, | |||
"total": 3 | |||
} |
@@ -1,7 +0,0 @@ | |||
{ | |||
"customMeasures": [ | |||
], | |||
"p": 1, | |||
"ps": 100, | |||
"total": 0 | |||
} |
@@ -1,17 +0,0 @@ | |||
{ | |||
"projectId": "project-uuid", | |||
"projectKey": "project-key", | |||
"metric": { | |||
"key": "metric-key", | |||
"type": "STRING" | |||
}, | |||
"value": "new-text-measure-value", | |||
"description": "new-custom-measure-description", | |||
"pending":true, | |||
"user": { | |||
"active": true, | |||
"email": "login@login.com", | |||
"login": "login", | |||
"name": "Login" | |||
} | |||
} |
@@ -872,203 +872,6 @@ | |||
} | |||
] | |||
}, | |||
{ | |||
"path": "api/custom_measures", | |||
"since": "5.2", | |||
"description": "Manage custom measures for a project. See also api/metrics.", | |||
"actions": [ | |||
{ | |||
"key": "create", | |||
"description": "Create a custom measure.<br /> The project id or the project key must be provided (only project and module custom measures can be created). The metric id or the metric key must be provided.<br/>Requires 'Administer System' permission or 'Administer' permission on the project.", | |||
"since": "5.2", | |||
"internal": false, | |||
"post": true, | |||
"hasResponseExample": false, | |||
"changelog": [], | |||
"params": [ | |||
{ | |||
"key": "description", | |||
"description": "Description", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "Team size growing." | |||
}, | |||
{ | |||
"key": "metricId", | |||
"description": "Metric id", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "16" | |||
}, | |||
{ | |||
"key": "metricKey", | |||
"description": "Metric key", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "ncloc" | |||
}, | |||
{ | |||
"key": "projectId", | |||
"description": "Project id", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "ce4c03d6-430f-40a9-b777-ad877c00aa4d" | |||
}, | |||
{ | |||
"key": "projectKey", | |||
"description": "Project key", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "my_project" | |||
}, | |||
{ | |||
"key": "value", | |||
"description": "Measure value. Value type depends on metric type:<ul><li>INT - type: integer</li><li>FLOAT - type: double</li><li>PERCENT - type: double</li><li>BOOL - the possible values are true or false</li><li>STRING - type: string</li><li>MILLISEC - type: integer</li><li>DATA - type: string</li><li>LEVEL - the possible values are OK, WARN, ERROR</li><li>DISTRIB - type: string</li><li>RATING - type: double</li><li>WORK_DUR - long representing the number of minutes</li></ul>", | |||
"required": true, | |||
"internal": false, | |||
"exampleValue": "47" | |||
} | |||
] | |||
}, | |||
{ | |||
"key": "delete", | |||
"description": "Delete a custom measure.<br /> Requires 'Administer System' permission or 'Administer' permission on the project.", | |||
"since": "5.2", | |||
"internal": false, | |||
"post": true, | |||
"hasResponseExample": false, | |||
"changelog": [], | |||
"params": [ | |||
{ | |||
"key": "id", | |||
"description": "Id", | |||
"required": true, | |||
"internal": false, | |||
"exampleValue": "24" | |||
} | |||
] | |||
}, | |||
{ | |||
"key": "metrics", | |||
"description": "List all custom metrics for which no custom measure already exists on a given project.<br /> The project id or project key must be provided.<br />Requires 'Administer System' permission or 'Administer' permission on the project.", | |||
"since": "5.2", | |||
"internal": true, | |||
"post": false, | |||
"hasResponseExample": true, | |||
"changelog": [], | |||
"params": [ | |||
{ | |||
"key": "projectId", | |||
"description": "Project id", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "ce4c03d6-430f-40a9-b777-ad877c00aa4d" | |||
}, | |||
{ | |||
"key": "projectKey", | |||
"description": "Project key", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "my_project" | |||
} | |||
] | |||
}, | |||
{ | |||
"key": "search", | |||
"description": "List custom measures. The project id or project key must be provided.<br />Requires 'Administer System' permission or 'Administer' permission on the project.", | |||
"since": "5.2", | |||
"internal": false, | |||
"post": false, | |||
"hasResponseExample": true, | |||
"changelog": [], | |||
"params": [ | |||
{ | |||
"key": "f", | |||
"description": "Comma-separated list of the fields to be returned in response. All the fields are returned by default.", | |||
"required": false, | |||
"internal": false, | |||
"possibleValues": [ | |||
"projectId", | |||
"projectKey", | |||
"value", | |||
"description", | |||
"metric", | |||
"createdAt", | |||
"updatedAt", | |||
"user", | |||
"pending" | |||
] | |||
}, | |||
{ | |||
"key": "p", | |||
"description": "1-based page number", | |||
"required": false, | |||
"internal": false, | |||
"defaultValue": "1", | |||
"exampleValue": "42", | |||
"deprecatedKey": "pageIndex", | |||
"deprecatedKeySince": "5.2" | |||
}, | |||
{ | |||
"key": "projectId", | |||
"description": "Project id", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "ce4c03d6-430f-40a9-b777-ad877c00aa4d" | |||
}, | |||
{ | |||
"key": "projectKey", | |||
"description": "Project key", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "my_project" | |||
}, | |||
{ | |||
"key": "ps", | |||
"description": "Page size. Must be greater than 0 and less than 500", | |||
"required": false, | |||
"internal": false, | |||
"defaultValue": "100", | |||
"exampleValue": "20", | |||
"deprecatedKey": "pageSize", | |||
"deprecatedKeySince": "5.2", | |||
"maximumValue": 500 | |||
} | |||
] | |||
}, | |||
{ | |||
"key": "update", | |||
"description": "Update a custom measure. Value and/or description must be provided<br />Requires 'Administer System' permission or 'Administer' permission on the project.", | |||
"since": "5.2", | |||
"internal": false, | |||
"post": true, | |||
"hasResponseExample": false, | |||
"changelog": [], | |||
"params": [ | |||
{ | |||
"key": "description", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "Team size growing." | |||
}, | |||
{ | |||
"key": "id", | |||
"description": "id", | |||
"required": true, | |||
"internal": false, | |||
"exampleValue": "42" | |||
}, | |||
{ | |||
"key": "value", | |||
"description": "Measure value. Value type depends on metric type:<ul><li>INT - type: integer</li><li>FLOAT - type: double</li><li>PERCENT - type: double</li><li>BOOL - the possible values are true or false</li><li>STRING - type: string</li><li>MILLISEC - type: integer</li><li>DATA - type: string</li><li>LEVEL - the possible values are OK, WARN, ERROR</li><li>DISTRIB - type: string</li><li>RATING - type: double</li><li>WORK_DUR - long representing the number of minutes</li></ul>", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "true" | |||
} | |||
] | |||
} | |||
] | |||
}, | |||
{ | |||
"path": "api/duplications", | |||
"since": "4.4", |