You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

App.tsx 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import * as React from 'react';
  21. import { Helmet } from 'react-helmet-async';
  22. import ListFooter from 'sonar-ui-common/components/controls/ListFooter';
  23. import { translate } from 'sonar-ui-common/helpers/l10n';
  24. import {
  25. createMetric,
  26. deleteMetric,
  27. getMetricDomains,
  28. getMetrics,
  29. getMetricTypes,
  30. MetricsResponse,
  31. updateMetric
  32. } from '../../../api/metrics';
  33. import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
  34. import { MetricProps } from './Form';
  35. import Header from './Header';
  36. import List from './List';
  37. interface Props {}
  38. interface State {
  39. domains?: string[];
  40. loading: boolean;
  41. metrics?: T.Metric[];
  42. paging?: T.Paging;
  43. types?: string[];
  44. }
  45. const PAGE_SIZE = 50;
  46. export default class App extends React.PureComponent<Props, State> {
  47. mounted = false;
  48. state: State = { loading: true };
  49. componentDidMount() {
  50. this.mounted = true;
  51. this.fetchData();
  52. }
  53. componentWillUnmount() {
  54. this.mounted = false;
  55. }
  56. fetchData = () => {
  57. Promise.all([
  58. getMetricDomains(),
  59. getMetricTypes(),
  60. getMetrics({ isCustom: true, ps: PAGE_SIZE })
  61. ]).then(([domains, types, metricsResponse]) => {
  62. if (this.mounted) {
  63. this.setState({
  64. domains,
  65. loading: false,
  66. metrics: metricsResponse.metrics,
  67. paging: this.getPaging(metricsResponse),
  68. types
  69. });
  70. }
  71. }, this.stopLoading);
  72. };
  73. fetchMore = () => {
  74. const { paging } = this.state;
  75. if (paging) {
  76. this.setState({ loading: true });
  77. getMetrics({ isCustom: true, p: paging.pageIndex + 1, ps: PAGE_SIZE }).then(
  78. metricsResponse => {
  79. if (this.mounted) {
  80. this.setState(({ metrics = [] }: State) => ({
  81. loading: false,
  82. metrics: [...metrics, ...metricsResponse.metrics],
  83. paging: this.getPaging(metricsResponse)
  84. }));
  85. }
  86. },
  87. this.stopLoading
  88. );
  89. }
  90. };
  91. stopLoading = () => {
  92. if (this.mounted) {
  93. this.setState({ loading: false });
  94. }
  95. };
  96. getPaging = (response: MetricsResponse): T.Paging => ({
  97. pageIndex: response.p,
  98. pageSize: response.ps,
  99. total: response.total
  100. });
  101. handleCreate = (data: MetricProps) => {
  102. return createMetric(data).then(metric => {
  103. if (this.mounted) {
  104. this.setState(({ metrics = [], paging }: State) => ({
  105. metrics: [...metrics, metric],
  106. paging: paging && { ...paging, total: paging.total + 1 }
  107. }));
  108. }
  109. });
  110. };
  111. handleEdit = (data: { id: string } & MetricProps) => {
  112. return updateMetric(data).then(() => {
  113. if (this.mounted) {
  114. this.setState(({ metrics = [] }: State) => ({
  115. metrics: metrics.map(metric => (metric.id === data.id ? { ...metric, ...data } : metric))
  116. }));
  117. }
  118. });
  119. };
  120. handleDelete = (metricKey: string) => {
  121. return deleteMetric({ keys: metricKey }).then(() => {
  122. if (this.mounted) {
  123. this.setState(({ metrics = [], paging }: State) => ({
  124. metrics: metrics.filter(metric => metric.key !== metricKey),
  125. paging: paging && { ...paging, total: paging.total - 1 }
  126. }));
  127. }
  128. });
  129. };
  130. render() {
  131. const { domains, loading, metrics, paging, types } = this.state;
  132. return (
  133. <>
  134. <Suggestions suggestions="custom_metrics" />
  135. <Helmet defer={false} title={translate('custom_metrics.page')} />
  136. <div className="page page-limited" id="custom-metrics-page">
  137. <Header domains={domains} loading={loading} onCreate={this.handleCreate} types={types} />
  138. {metrics && (
  139. <List
  140. domains={domains}
  141. metrics={metrics}
  142. onDelete={this.handleDelete}
  143. onEdit={this.handleEdit}
  144. types={types}
  145. />
  146. )}
  147. {metrics && paging && (
  148. <ListFooter
  149. count={metrics.length}
  150. loadMore={this.fetchMore}
  151. ready={!loading}
  152. total={paging.total}
  153. />
  154. )}
  155. </div>
  156. </>
  157. );
  158. }
  159. }