Browse Source

SONAR-10762 remove Custom Metric UI

tags/9.1.0.47736
Zipeng WU 2 years ago
parent
commit
9b66bdef10
27 changed files with 2 additions and 1927 deletions
  1. 1
    34
      server/sonar-web/src/main/js/api/metrics.ts
  2. 0
    5
      server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.tsx
  3. 0
    16
      server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsNav-test.tsx.snap
  4. 0
    2
      server/sonar-web/src/main/js/app/utils/startReactApp.tsx
  5. 0
    174
      server/sonar-web/src/main/js/apps/custom-metrics/components/App.tsx
  6. 0
    76
      server/sonar-web/src/main/js/apps/custom-metrics/components/CreateButton.tsx
  7. 0
    60
      server/sonar-web/src/main/js/apps/custom-metrics/components/DeleteForm.tsx
  8. 0
    198
      server/sonar-web/src/main/js/apps/custom-metrics/components/Form.tsx
  9. 0
    50
      server/sonar-web/src/main/js/apps/custom-metrics/components/Header.tsx
  10. 0
    146
      server/sonar-web/src/main/js/apps/custom-metrics/components/Item.tsx
  11. 0
    57
      server/sonar-web/src/main/js/apps/custom-metrics/components/List.tsx
  12. 0
    77
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/App-test.tsx
  13. 0
    37
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/CreateButton-test.tsx
  14. 0
    29
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/DeleteForm-test.tsx
  15. 0
    90
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Form-test.tsx
  16. 0
    38
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Header-test.tsx
  17. 0
    66
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Item-test.tsx
  18. 0
    36
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/List-test.tsx
  19. 0
    136
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/App-test.tsx.snap
  20. 0
    41
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/CreateButton-test.tsx.snap
  21. 0
    45
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/DeleteForm-test.tsx.snap
  22. 0
    156
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Form-test.tsx.snap
  23. 0
    49
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Header-test.tsx.snap
  24. 0
    61
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Item-test.tsx.snap
  25. 0
    53
      server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/List-test.tsx.snap
  26. 0
    28
      server/sonar-web/src/main/js/apps/custom-metrics/routes.ts
  27. 1
    167
      sonar-ws-generator/src/main/resources/snapshot-of-api.json

+ 1
- 34
server/sonar-web/src/main/js/api/metrics.ts View File

@@ -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';

export interface MetricsResponse {
@@ -55,36 +55,3 @@ export function getAllMetrics(data?: {
});
}
}

export function getMetricDomains(): Promise<string[]> {
return getJSON('/api/metrics/domains').then(r => r.domains, throwGlobalError);
}

export function getMetricTypes(): Promise<string[]> {
return getJSON('/api/metrics/types').then(r => r.types, throwGlobalError);
}

export function createMetric(data: {
description?: string;
domain?: string;
key: string;
name: string;
type: string;
}): Promise<T.Metric> {
return postJSON('/api/metrics/create', data).catch(throwGlobalError);
}

export function updateMetric(data: {
description?: string;
domain?: string;
id: string;
key?: string;
name?: string;
type?: string;
}) {
return post('/api/metrics/update', data).catch(throwGlobalError);
}

export function deleteMetric(data: { keys: string }) {
return post('/api/metrics/delete', data).catch(throwGlobalError);
}

+ 0
- 5
server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.tsx View File

@@ -103,11 +103,6 @@ export default class SettingsNav extends React.PureComponent<Props> {
{translate('property.category.security.encryption')}
</IndexLink>
</li>
<li>
<IndexLink activeClassName="active" to="/admin/custom_metrics">
{translate('custom_metrics.page')}
</IndexLink>
</li>
<li>
<IndexLink activeClassName="active" to="/admin/webhooks">
{translate('webhooks.page')}

+ 0
- 16
server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsNav-test.tsx.snap View File

@@ -58,14 +58,6 @@ exports[`should work with extensions 1`] = `
property.category.security.encryption
</IndexLink>
</li>
<li>
<IndexLink
activeClassName="active"
to="/admin/custom_metrics"
>
custom_metrics.page
</IndexLink>
</li>
<li>
<IndexLink
activeClassName="active"
@@ -203,14 +195,6 @@ Array [
property.category.security.encryption
</IndexLink>
</li>
<li>
<IndexLink
activeClassName="active"
to="/admin/custom_metrics"
>
custom_metrics.page
</IndexLink>
</li>
<li>
<IndexLink
activeClassName="active"

+ 0
- 2
server/sonar-web/src/main/js/app/utils/startReactApp.tsx View File

@@ -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 customMetricsRoutes from '../../apps/custom-metrics/routes';
import documentationRoutes from '../../apps/documentation/routes';
import groupsRoutes from '../../apps/groups/routes';
import Issues from '../../apps/issues/components/AppContainer';
@@ -231,7 +230,6 @@ function renderAdminRoutes() {
)}
/>
<RouteWithChildRoutes path="background_tasks" childRoutes={backgroundTasksRoutes} />
<RouteWithChildRoutes path="custom_metrics" childRoutes={customMetricsRoutes} />
<RouteWithChildRoutes path="groups" childRoutes={groupsRoutes} />
<RouteWithChildRoutes path="permission_templates" childRoutes={permissionTemplatesRoutes} />
<RouteWithChildRoutes path="permissions" childRoutes={globalPermissionsRoutes} />

+ 0
- 174
server/sonar-web/src/main/js/apps/custom-metrics/components/App.tsx View File

@@ -1,174 +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 {
createMetric,
deleteMetric,
getMetricDomains,
getMetrics,
getMetricTypes,
MetricsResponse,
updateMetric
} from '../../../api/metrics';
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import { MetricProps } from './Form';
import Header from './Header';
import List from './List';

interface Props {}

interface State {
domains?: string[];
loading: boolean;
metrics?: T.Metric[];
paging?: T.Paging;
types?: string[];
}

const PAGE_SIZE = 50;

export default class App extends React.PureComponent<Props, State> {
mounted = false;
state: State = { loading: true };

componentDidMount() {
this.mounted = true;
this.fetchData();
}

componentWillUnmount() {
this.mounted = false;
}

fetchData = () => {
Promise.all([
getMetricDomains(),
getMetricTypes(),
getMetrics({ isCustom: true, ps: PAGE_SIZE })
]).then(([domains, types, metricsResponse]) => {
if (this.mounted) {
this.setState({
domains,
loading: false,
metrics: metricsResponse.metrics,
paging: this.getPaging(metricsResponse),
types
});
}
}, this.stopLoading);
};

fetchMore = () => {
const { paging } = this.state;
if (paging) {
this.setState({ loading: true });
getMetrics({ isCustom: true, p: paging.pageIndex + 1, ps: PAGE_SIZE }).then(
metricsResponse => {
if (this.mounted) {
this.setState(({ metrics = [] }: State) => ({
loading: false,
metrics: [...metrics, ...metricsResponse.metrics],
paging: this.getPaging(metricsResponse)
}));
}
},
this.stopLoading
);
}
};

stopLoading = () => {
if (this.mounted) {
this.setState({ loading: false });
}
};

getPaging = (response: MetricsResponse): T.Paging => ({
pageIndex: response.p,
pageSize: response.ps,
total: response.total
});

handleCreate = (data: MetricProps) => {
return createMetric(data).then(metric => {
if (this.mounted) {
this.setState(({ metrics = [], paging }: State) => ({
metrics: [...metrics, metric],
paging: paging && { ...paging, total: paging.total + 1 }
}));
}
});
};

handleEdit = (data: { id: string } & MetricProps) => {
return updateMetric(data).then(() => {
if (this.mounted) {
this.setState(({ metrics = [] }: State) => ({
metrics: metrics.map(metric => (metric.id === data.id ? { ...metric, ...data } : metric))
}));
}
});
};

handleDelete = (metricKey: string) => {
return deleteMetric({ keys: metricKey }).then(() => {
if (this.mounted) {
this.setState(({ metrics = [], paging }: State) => ({
metrics: metrics.filter(metric => metric.key !== metricKey),
paging: paging && { ...paging, total: paging.total - 1 }
}));
}
});
};

render() {
const { domains, loading, metrics, paging, types } = this.state;

return (
<>
<Suggestions suggestions="custom_metrics" />
<Helmet defer={false} title={translate('custom_metrics.page')} />
<div className="page page-limited" id="custom-metrics-page">
<Header domains={domains} loading={loading} onCreate={this.handleCreate} types={types} />
{metrics && (
<List
domains={domains}
metrics={metrics}
onDelete={this.handleDelete}
onEdit={this.handleEdit}
types={types}
/>
)}
{metrics && paging && (
<ListFooter
count={metrics.length}
loadMore={this.fetchMore}
ready={!loading}
total={paging.total}
/>
)}
</div>
</>
);
}
}

+ 0
- 76
server/sonar-web/src/main/js/apps/custom-metrics/components/CreateButton.tsx View File

@@ -1,76 +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, { MetricProps } from './Form';

interface Props {
domains: string[];
onCreate: (data: MetricProps) => Promise<void>;
types: string[];
}

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="metrics-create" onClick={this.handleClick}>
{translate('custom_metrics.create_metric')}
</Button>
{this.state.modal && (
<Form
confirmButtonText={translate('create')}
domains={this.props.domains}
header={translate('custom_metrics.create_metric')}
onClose={this.handleClose}
onSubmit={this.props.onCreate}
types={this.props.types}
/>
)}
</>
);
}
}

+ 0
- 60
server/sonar-web/src/main/js/apps/custom-metrics/components/DeleteForm.tsx View File

@@ -1,60 +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 {
metric: T.Metric;
onClose: () => void;
onSubmit: () => Promise<void>;
}

export default function DeleteForm({ metric, onClose, onSubmit }: Props) {
const header = translate('custom_metrics.delete_metric');

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_metrics.delete_metric.confirmation', 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>
);
}

+ 0
- 198
server/sonar-web/src/main/js/apps/custom-metrics/components/Form.tsx View File

@@ -1,198 +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, { Creatable } from 'sonar-ui-common/components/controls/Select';
import SimpleModal from 'sonar-ui-common/components/controls/SimpleModal';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import MandatoryFieldMarker from 'sonar-ui-common/components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from 'sonar-ui-common/components/ui/MandatoryFieldsExplanation';
import { translate } from 'sonar-ui-common/helpers/l10n';

export interface MetricProps {
description: string;
domain?: string;
key: string;
name: string;
type: string;
}

interface Props {
confirmButtonText: string;
domains: string[];
metric?: T.Metric;
header: string;
onClose: () => void;
onSubmit: (data: MetricProps) => Promise<void>;
types: string[];
}

interface State extends MetricProps {}

export default class Form extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
description: (props.metric && props.metric.description) || '',
domain: props.metric && props.metric.domain,
key: (props.metric && props.metric.key) || '',
name: (props.metric && props.metric.name) || '',
type: (props.metric && props.metric.type) || 'INT'
};
}

handleSubmit = () => {
return this.props
.onSubmit({
description: this.state.description,
domain: this.state.domain,
key: this.state.key,
name: this.state.name,
type: this.state.type
})
.then(this.props.onClose);
};

handleKeyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ key: event.currentTarget.value });
};

handleDescriptionChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
this.setState({ description: event.currentTarget.value });
};

handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ name: event.currentTarget.value });
};

handleDomainChange = (option: { value: string } | null) => {
this.setState({ domain: option ? option.value : undefined });
};

handleTypeChange = ({ value }: { value: string }) => {
this.setState({ type: value });
};

render() {
const domains = [...this.props.domains];
if (this.state.domain) {
domains.push(this.state.domain);
}

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 modal-container">
<MandatoryFieldsExplanation className="modal-field" />

<div className="modal-field">
<label htmlFor="create-metric-key">
{translate('key')}
<MandatoryFieldMarker />
</label>
<input
autoFocus={true}
id="create-metric-key"
maxLength={64}
name="key"
onChange={this.handleKeyChange}
required={true}
type="text"
value={this.state.key}
/>
</div>
<div className="modal-field">
<label htmlFor="create-metric-name">
{translate('name')}
<MandatoryFieldMarker />
</label>
<input
id="create-metric-name"
maxLength={64}
name="name"
onChange={this.handleNameChange}
required={true}
type="text"
value={this.state.name}
/>
</div>
<div className="modal-field">
<label htmlFor="create-metric-description">{translate('description')}</label>
<textarea
id="create-metric-description"
name="description"
onChange={this.handleDescriptionChange}
value={this.state.description}
/>
</div>
<div className="modal-field">
<label htmlFor="create-metric-domain">{translate('custom_metrics.domain')}</label>
<Creatable
id="create-metric-domain"
onChange={this.handleDomainChange}
options={domains.map(domain => ({ label: domain, value: domain }))}
value={this.state.domain}
/>
</div>
<div className="modal-field">
<label htmlFor="create-metric-type">
{translate('type')}
<MandatoryFieldMarker />
</label>
<Select
clearable={false}
id="create-metric-type"
onChange={this.handleTypeChange}
options={this.props.types.map(type => ({
label: translate('metric.type', type),
value: type
}))}
value={this.state.type}
/>
</div>
</div>

<footer className="modal-foot">
<DeferredSpinner className="spacer-right" loading={submitting} />
<SubmitButton disabled={submitting} id="create-metric-submit">
{this.props.confirmButtonText}
</SubmitButton>
<ResetButtonLink
disabled={submitting}
id="create-metric-cancel"
onClick={onCloseClick}>
{translate('cancel')}
</ResetButtonLink>
</footer>
</form>
)}
</SimpleModal>
);
}
}

+ 0
- 50
server/sonar-web/src/main/js/apps/custom-metrics/components/Header.tsx View File

@@ -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 { 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';
import { MetricProps } from './Form';

interface Props {
domains: string[] | undefined;
loading: boolean;
onCreate: (data: MetricProps) => Promise<void>;
types: string[] | undefined;
}

export default function Header({ domains, loading, onCreate, types }: Props) {
return (
<header className="page-header" id="custom-metrics-header">
<h1 className="page-title">{translate('custom_metrics.page')}</h1>
<DeferredSpinner loading={loading} />
<div className="page-actions">
{domains && types && <CreateButton domains={domains} onCreate={onCreate} types={types} />}
</div>
<div className="page-description">
<Alert display="inline" variant="error">
{translate('custom_metrics.deprecated')}
</Alert>
<p>{translate('custom_metrics.page.description')}</p>
</div>
</header>
);
}

+ 0
- 146
server/sonar-web/src/main/js/apps/custom-metrics/components/Item.tsx View File

@@ -1,146 +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 { translate } from 'sonar-ui-common/helpers/l10n';
import DeleteForm from './DeleteForm';
import Form, { MetricProps } from './Form';

interface Props {
domains?: string[];
metric: T.Metric;
onDelete: (metricKey: string) => Promise<void>;
onEdit: (data: { id: string } & MetricProps) => Promise<void>;
types?: string[];
}

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: MetricProps) => {
return this.props.onEdit({ id: this.props.metric.id, ...data });
};

handleDeleteFormSubmit = () => {
return this.props.onDelete(this.props.metric.key);
};

render() {
const { domains, metric, types } = this.props;

return (
<tr data-metric={metric.key}>
<td className="width-30">
<div>
<strong className="js-metric-name">{metric.name}</strong>
<span className="js-metric-key note little-spacer-left">{metric.key}</span>
</div>
</td>

<td className="width-20">
<span className="js-metric-domain">{metric.domain}</span>
</td>

<td className="width-20">
<span className="js-metric-type">{translate('metric.type', metric.type)}</span>
</td>

<td className="width-20" title={metric.description}>
<span className="js-metric-description">{metric.description}</span>
</td>

<td className="thin nowrap">
<ActionsDropdown>
{domains && types && (
<ActionsDropdownItem className="js-metric-update" onClick={this.handleEditClick}>
{translate('update_details')}
</ActionsDropdownItem>
)}
<ActionsDropdownDivider />
<ActionsDropdownItem
className="js-metric-delete"
destructive={true}
onClick={this.handleDeleteClick}>
{translate('delete')}
</ActionsDropdownItem>
</ActionsDropdown>
</td>

{this.state.editForm && domains && types && (
<Form
confirmButtonText={translate('update_verb')}
domains={domains}
header={translate('custom_metrics.update_metric')}
metric={metric}
onClose={this.closeEditForm}
onSubmit={this.handleEditFormSubmit}
types={types}
/>
)}

{this.state.deleteForm && (
<DeleteForm
metric={metric}
onClose={this.closeDeleteForm}
onSubmit={this.handleDeleteFormSubmit}
/>
)}
</tr>
);
}
}

+ 0
- 57
server/sonar-web/src/main/js/apps/custom-metrics/components/List.tsx View File

@@ -1,57 +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 { MetricProps } from './Form';
import Item from './Item';

interface Props {
domains?: string[];
metrics: T.Metric[];
onDelete: (metricKey: string) => Promise<void>;
onEdit: (data: { id: string } & MetricProps) => Promise<void>;
types?: string[];
}

export default function List({ domains, metrics, onDelete, onEdit, types }: Props) {
return (
<div className="boxed-group boxed-group-inner" id="custom-metrics-list">
{metrics.length > 0 ? (
<table className="data zebra zebra-hover">
<tbody>
{sortBy(metrics, metric => metric.name.toLowerCase()).map(metric => (
<Item
domains={domains}
key={metric.key}
metric={metric}
onDelete={onDelete}
onEdit={onEdit}
types={types}
/>
))}
</tbody>
</table>
) : (
<p>{translate('no_results')}</p>
)}
</div>
);
}

+ 0
- 77
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/App-test.tsx View File

@@ -1,77 +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/metrics', () => ({
getMetricDomains: () => Promise.resolve(['Coverage', 'Issues']),
getMetricTypes: () => Promise.resolve(['INT', 'STRING']),
getMetrics: () =>
Promise.resolve({
metrics: [{ id: '3', key: 'foo', name: 'Foo', type: 'INT' }],
p: 1,
ps: 1,
total: 1
}),
deleteMetric: () => Promise.resolve(),
updateMetric: () => Promise.resolve(),
createMetric: () =>
Promise.resolve({ id: '4', domain: 'Coverage', key: 'bar', name: 'Bar', type: 'INT' })
}));

it('should work', async () => {
const wrapper = shallow<App>(<App />);
wrapper.instance().mounted = true;
expect(wrapper).toMatchSnapshot();

await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();

// create
wrapper.find('Header').prop<Function>('onCreate')({
domain: 'Coverage',
key: 'bar',
name: 'Bar',
type: 'INT'
});
await waitAndUpdate(wrapper);
expect(wrapper.state().metrics).toMatchSnapshot();
expect(wrapper.state().paging!.total).toBe(2);

// edit
wrapper.find('List').prop<Function>('onEdit')({
domain: undefined,
id: '4',
key: 'bar',
name: 'Bar',
type: 'STRING'
});
await waitAndUpdate(wrapper);
expect(wrapper.state().metrics).toMatchSnapshot();
expect(wrapper.state().paging!.total).toBe(2);

// delete
wrapper.find('List').prop<Function>('onDelete')('bar');
await waitAndUpdate(wrapper);
expect(wrapper.state().metrics).toMatchSnapshot();
expect(wrapper.state().paging!.total).toBe(1);
});

+ 0
- 37
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/CreateButton-test.tsx View File

@@ -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 { click } from 'sonar-ui-common/helpers/testUtils';
import CreateButton from '../CreateButton';

it('should create new group', () => {
const onCreate = jest.fn(() => Promise.resolve());
const wrapper = shallow(
<CreateButton domains={['Coverage', 'Issues']} onCreate={onCreate} types={['INT', 'STRING']} />
);
expect(wrapper).toMatchSnapshot();

click(wrapper.find('#metrics-create'));
expect(wrapper).toMatchSnapshot();

wrapper.find('Form').prop<Function>('onSubmit')({ key: 'foo', name: 'foo', type: 'INT' });
expect(onCreate).toBeCalledWith({ key: 'foo', name: 'foo', type: 'INT' });
});

+ 0
- 29
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/DeleteForm-test.tsx View File

@@ -1,29 +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 metric = { id: '3', key: 'foo', name: 'Foo', type: 'INT' };
expect(
shallow(<DeleteForm metric={metric} onClose={jest.fn()} onSubmit={jest.fn()} />).dive()
).toMatchSnapshot();
});

+ 0
- 90
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Form-test.tsx View File

@@ -1,90 +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 } from 'sonar-ui-common/helpers/testUtils';
import Form from '../Form';

it('should render form', async () => {
const onClose = jest.fn();
const onSubmit = jest.fn(() => Promise.resolve());
const wrapper = shallow(
<Form
confirmButtonText="confirmButtonText"
domains={['Coverage', 'Issues']}
header="header"
onClose={onClose}
onSubmit={onSubmit}
types={['INT', 'STRING']}
/>
).dive();
expect(wrapper).toMatchSnapshot();

change(wrapper.find('[name="key"]'), 'foo');
change(wrapper.find('[name="name"]'), 'Foo');
change(wrapper.find('[name="description"]'), 'bar');
wrapper.find('Creatable').prop<Function>('onChange')({ value: 'Coverage' });
submit(wrapper.find('form'));
expect(onSubmit).toBeCalledWith({
description: 'bar',
domain: 'Coverage',
key: 'foo',
name: 'Foo',
type: 'INT'
});

await new Promise(setImmediate);
expect(onClose).toBeCalled();

onClose.mockClear();
click(wrapper.find('ResetButtonLink'));
expect(onClose).toBeCalled();
});

it('should create new domain', () => {
const wrapper = shallow(
<Form
confirmButtonText="confirmButtonText"
domains={['Coverage', 'Issues']}
header="header"
onClose={jest.fn()}
onSubmit={jest.fn()}
types={['INT', 'STRING']}
/>
);

const optionsBefore = [
{ label: 'Coverage', value: 'Coverage' },
{ label: 'Issues', value: 'Issues' }
];
expect(getSelect().prop('options')).toEqual(optionsBefore);

getSelect().prop<Function>('onChange')({ value: 'Another' });
wrapper.update();

expect(getSelect().prop('options')).toEqual([
...optionsBefore,
{ label: 'Another', value: 'Another' }
]);

function getSelect() {
return wrapper.dive().find('Creatable');
}
});

+ 0
- 38
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Header-test.tsx View File

@@ -1,38 +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 metric', () => {
const onCreate = jest.fn(() => Promise.resolve());
const wrapper = shallow(
<Header
domains={['Coverage', 'Issues']}
loading={false}
onCreate={onCreate}
types={['INT', 'STRING']}
/>
);
expect(wrapper).toMatchSnapshot();

wrapper.find('CreateButton').prop<Function>('onCreate')({ key: 'foo', name: 'Foo', type: 'INT' });
expect(onCreate).toBeCalledWith({ key: 'foo', name: 'Foo', type: 'INT' });
});

+ 0
- 66
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Item-test.tsx View File

@@ -1,66 +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 metric = { id: '3', key: 'foo', name: 'Foo', type: 'INT' };

it('should render', () => {
expect(
shallow(<Item metric={metric} onDelete={jest.fn()} onEdit={jest.fn()} />)
).toMatchSnapshot();
});

it('should edit metric', () => {
const onEdit = jest.fn();

const wrapper = shallow(
<Item
domains={['Coverage', 'Issues']}
metric={metric}
onDelete={jest.fn()}
onEdit={onEdit}
types={['INT', 'STRING']}
/>
);

click(wrapper.find('.js-metric-update'));
wrapper.update();

wrapper.find('Form').prop<Function>('onSubmit')({
...metric,
description: 'bla bla',
domain: 'Coverage'
});
expect(onEdit).toBeCalledWith({ ...metric, description: 'bla bla', domain: 'Coverage' });
});

it('should delete metric', () => {
const onDelete = jest.fn();
const wrapper = shallow(<Item metric={metric} onDelete={onDelete} onEdit={jest.fn()} />);

click(wrapper.find('.js-metric-delete'));
wrapper.update();

wrapper.find('DeleteForm').prop<Function>('onSubmit')();
expect(onDelete).toBeCalledWith('foo');
});

+ 0
- 36
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/List-test.tsx View File

@@ -1,36 +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 metrics = [
{ id: '3', key: 'foo', name: 'Foo', type: 'INT' },
{ id: '4', domain: 'Coverage', key: 'bar', name: 'Bar', type: 'INT' }
];
expect(
shallow(<List metrics={metrics} onDelete={jest.fn()} onEdit={jest.fn()} />)
).toMatchSnapshot();
});

it('should render no results', () => {
expect(shallow(<List metrics={[]} onDelete={jest.fn()} onEdit={jest.fn()} />)).toMatchSnapshot();
});

+ 0
- 136
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/App-test.tsx.snap View File

@@ -1,136 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should work 1`] = `
<Fragment>
<Suggestions
suggestions="custom_metrics"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="custom_metrics.page"
/>
<div
className="page page-limited"
id="custom-metrics-page"
>
<Header
loading={true}
onCreate={[Function]}
/>
</div>
</Fragment>
`;

exports[`should work 2`] = `
<Fragment>
<Suggestions
suggestions="custom_metrics"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="custom_metrics.page"
/>
<div
className="page page-limited"
id="custom-metrics-page"
>
<Header
domains={
Array [
"Coverage",
"Issues",
]
}
loading={false}
onCreate={[Function]}
types={
Array [
"INT",
"STRING",
]
}
/>
<List
domains={
Array [
"Coverage",
"Issues",
]
}
metrics={
Array [
Object {
"id": "3",
"key": "foo",
"name": "Foo",
"type": "INT",
},
]
}
onDelete={[Function]}
onEdit={[Function]}
types={
Array [
"INT",
"STRING",
]
}
/>
<ListFooter
count={1}
loadMore={[Function]}
ready={true}
total={1}
/>
</div>
</Fragment>
`;

exports[`should work 3`] = `
Array [
Object {
"id": "3",
"key": "foo",
"name": "Foo",
"type": "INT",
},
Object {
"domain": "Coverage",
"id": "4",
"key": "bar",
"name": "Bar",
"type": "INT",
},
]
`;

exports[`should work 4`] = `
Array [
Object {
"id": "3",
"key": "foo",
"name": "Foo",
"type": "INT",
},
Object {
"domain": undefined,
"id": "4",
"key": "bar",
"name": "Bar",
"type": "STRING",
},
]
`;

exports[`should work 5`] = `
Array [
Object {
"id": "3",
"key": "foo",
"name": "Foo",
"type": "INT",
},
]
`;

+ 0
- 41
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/CreateButton-test.tsx.snap View File

@@ -1,41 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should create new group 1`] = `
<Fragment>
<Button
id="metrics-create"
onClick={[Function]}
>
custom_metrics.create_metric
</Button>
</Fragment>
`;

exports[`should create new group 2`] = `
<Fragment>
<Button
id="metrics-create"
onClick={[Function]}
>
custom_metrics.create_metric
</Button>
<Form
confirmButtonText="create"
domains={
Array [
"Coverage",
"Issues",
]
}
header="custom_metrics.create_metric"
onClose={[Function]}
onSubmit={[MockFunction]}
types={
Array [
"INT",
"STRING",
]
}
/>
</Fragment>
`;

+ 0
- 45
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/DeleteForm-test.tsx.snap View File

@@ -1,45 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render 1`] = `
<Modal
contentLabel="custom_metrics.delete_metric"
onRequestClose={[MockFunction]}
>
<form
onSubmit={[Function]}
>
<header
className="modal-head"
>
<h2>
custom_metrics.delete_metric
</h2>
</header>
<div
className="modal-body"
>
custom_metrics.delete_metric.confirmation.Foo
</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>
`;

+ 0
- 156
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Form-test.tsx.snap View File

@@ -1,156 +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 modal-container"
>
<MandatoryFieldsExplanation
className="modal-field"
/>
<div
className="modal-field"
>
<label
htmlFor="create-metric-key"
>
key
<MandatoryFieldMarker />
</label>
<input
autoFocus={true}
id="create-metric-key"
maxLength={64}
name="key"
onChange={[Function]}
required={true}
type="text"
value=""
/>
</div>
<div
className="modal-field"
>
<label
htmlFor="create-metric-name"
>
name
<MandatoryFieldMarker />
</label>
<input
id="create-metric-name"
maxLength={64}
name="name"
onChange={[Function]}
required={true}
type="text"
value=""
/>
</div>
<div
className="modal-field"
>
<label
htmlFor="create-metric-description"
>
description
</label>
<textarea
id="create-metric-description"
name="description"
onChange={[Function]}
value=""
/>
</div>
<div
className="modal-field"
>
<label
htmlFor="create-metric-domain"
>
custom_metrics.domain
</label>
<Creatable
id="create-metric-domain"
onChange={[Function]}
options={
Array [
Object {
"label": "Coverage",
"value": "Coverage",
},
Object {
"label": "Issues",
"value": "Issues",
},
]
}
/>
</div>
<div
className="modal-field"
>
<label
htmlFor="create-metric-type"
>
type
<MandatoryFieldMarker />
</label>
<Select
clearable={false}
id="create-metric-type"
onChange={[Function]}
options={
Array [
Object {
"label": "metric.type.INT",
"value": "INT",
},
Object {
"label": "metric.type.STRING",
"value": "STRING",
},
]
}
value="INT"
/>
</div>
</div>
<footer
className="modal-foot"
>
<DeferredSpinner
className="spacer-right"
loading={false}
/>
<SubmitButton
disabled={false}
id="create-metric-submit"
>
confirmButtonText
</SubmitButton>
<ResetButtonLink
disabled={false}
id="create-metric-cancel"
onClick={[Function]}
>
cancel
</ResetButtonLink>
</footer>
</form>
</Modal>
`;

+ 0
- 49
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Header-test.tsx.snap View File

@@ -1,49 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should create new metric 1`] = `
<header
className="page-header"
id="custom-metrics-header"
>
<h1
className="page-title"
>
custom_metrics.page
</h1>
<DeferredSpinner
loading={false}
/>
<div
className="page-actions"
>
<CreateButton
domains={
Array [
"Coverage",
"Issues",
]
}
onCreate={[MockFunction]}
types={
Array [
"INT",
"STRING",
]
}
/>
</div>
<div
className="page-description"
>
<Alert
display="inline"
variant="error"
>
custom_metrics.deprecated
</Alert>
<p>
custom_metrics.page.description
</p>
</div>
</header>
`;

+ 0
- 61
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Item-test.tsx.snap View File

@@ -1,61 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render 1`] = `
<tr
data-metric="foo"
>
<td
className="width-30"
>
<div>
<strong
className="js-metric-name"
>
Foo
</strong>
<span
className="js-metric-key note little-spacer-left"
>
foo
</span>
</div>
</td>
<td
className="width-20"
>
<span
className="js-metric-domain"
/>
</td>
<td
className="width-20"
>
<span
className="js-metric-type"
>
metric.type.INT
</span>
</td>
<td
className="width-20"
>
<span
className="js-metric-description"
/>
</td>
<td
className="thin nowrap"
>
<ActionsDropdown>
<ActionsDropdownDivider />
<ActionsDropdownItem
className="js-metric-delete"
destructive={true}
onClick={[Function]}
>
delete
</ActionsDropdownItem>
</ActionsDropdown>
</td>
</tr>
`;

+ 0
- 53
server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/List-test.tsx.snap View File

@@ -1,53 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render 1`] = `
<div
className="boxed-group boxed-group-inner"
id="custom-metrics-list"
>
<table
className="data zebra zebra-hover"
>
<tbody>
<Item
key="bar"
metric={
Object {
"domain": "Coverage",
"id": "4",
"key": "bar",
"name": "Bar",
"type": "INT",
}
}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
<Item
key="foo"
metric={
Object {
"id": "3",
"key": "foo",
"name": "Foo",
"type": "INT",
}
}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
</tbody>
</table>
</div>
`;

exports[`should render no results 1`] = `
<div
className="boxed-group boxed-group-inner"
id="custom-metrics-list"
>
<p>
no_results
</p>
</div>
`;

+ 0
- 28
server/sonar-web/src/main/js/apps/custom-metrics/routes.ts View File

@@ -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;

+ 1
- 167
sonar-ws-generator/src/main/resources/snapshot-of-api.json View File

@@ -2547,105 +2547,8 @@
{
"path": "api/metrics",
"since": "2.6",
"description": "Get information on automatic metrics, and manage custom metrics. See also api/custom_measures.",
"description": "Get information on automatic metrics, and manage metrics.",
"actions": [
{
"key": "create",
"description": "Create custom metric.<br /> Requires 'Administer System' permission.",
"since": "5.2",
"internal": false,
"post": true,
"hasResponseExample": false,
"changelog": [],
"params": [
{
"key": "description",
"description": "Description",
"required": false,
"internal": false,
"exampleValue": "Size of the team",
"maximumLength": 255
},
{
"key": "domain",
"description": "Domain",
"required": false,
"internal": false,
"exampleValue": "Tests",
"maximumLength": 64
},
{
"key": "key",
"description": "Key",
"required": true,
"internal": false,
"exampleValue": "team_size",
"maximumLength": 64
},
{
"key": "name",
"description": "Name",
"required": true,
"internal": false,
"exampleValue": "Team Size",
"maximumLength": 64
},
{
"key": "type",
"description": "Metric type key",
"required": true,
"internal": false,
"exampleValue": "INT",
"possibleValues": [
"INT",
"FLOAT",
"PERCENT",
"BOOL",
"STRING",
"MILLISEC",
"DATA",
"LEVEL",
"DISTRIB",
"RATING",
"WORK_DUR"
]
}
]
},
{
"key": "delete",
"description": "Delete metrics and associated measures. Delete only custom metrics.<br />Ids or keys must be provided. <br />Requires 'Administer System' permission.",
"since": "5.2",
"internal": false,
"post": true,
"hasResponseExample": false,
"changelog": [],
"params": [
{
"key": "ids",
"description": "Metrics ids to delete.",
"required": false,
"internal": false,
"exampleValue": "5, 23, 42"
},
{
"key": "keys",
"description": "Metrics keys to delete",
"required": false,
"internal": false,
"exampleValue": "team_size, business_value"
}
]
},
{
"key": "domains",
"description": "List all custom metric domains.",
"since": "5.2",
"internal": false,
"post": false,
"hasResponseExample": true,
"changelog": []
},
{
"key": "search",
"description": "Search for metrics",
@@ -2709,75 +2612,6 @@
"post": false,
"hasResponseExample": true,
"changelog": []
},
{
"key": "update",
"description": "Update a custom metric.<br /> Requires 'Administer System' permission.",
"since": "5.2",
"internal": false,
"post": true,
"hasResponseExample": false,
"changelog": [],
"params": [
{
"key": "description",
"description": "Description",
"required": false,
"internal": false,
"exampleValue": "Size of the team",
"maximumLength": 255
},
{
"key": "domain",
"description": "Domain",
"required": false,
"internal": false,
"exampleValue": "Tests",
"maximumLength": 64
},
{
"key": "id",
"description": "Id of the custom metric to update",
"required": true,
"internal": false,
"exampleValue": "42"
},
{
"key": "key",
"description": "Key",
"required": false,
"internal": false,
"exampleValue": "team_size",
"maximumLength": 64
},
{
"key": "name",
"description": "Name",
"required": false,
"internal": false,
"maximumLength": 64
},
{
"key": "type",
"description": "Metric type key",
"required": false,
"internal": false,
"exampleValue": "INT",
"possibleValues": [
"INT",
"FLOAT",
"PERCENT",
"BOOL",
"STRING",
"MILLISEC",
"DATA",
"LEVEL",
"DISTRIB",
"RATING",
"WORK_DUR"
]
}
]
}
]
},

Loading…
Cancel
Save