aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStas Vilchik <stas.vilchik@sonarsource.com>2018-08-22 13:06:28 +0200
committerSonarTech <sonartech@sonarsource.com>2018-08-22 20:21:22 +0200
commitaf00018774baa18f3539560de991e747cba74848 (patch)
treec2686b4fec9cfa82e5ff2ef502e89a70bae5e25e
parent8de7653276bfef55580ad8a09cb9ba0c957e515b (diff)
downloadsonarqube-af00018774baa18f3539560de991e747cba74848.tar.gz
sonarqube-af00018774baa18f3539560de991e747cba74848.zip
drop favorites from redux store (#631)
-rw-r--r--server/sonar-web/src/main/js/api/components.ts5
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts4
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/MeasureFavoriteContainer.js103
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/MeasureFavoriteContainer.tsx86
-rw-r--r--server/sonar-web/src/main/js/apps/component/components/__tests__/__snapshots__/App-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx34
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx171
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx9
-rw-r--r--server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx26
-rw-r--r--server/sonar-web/src/main/js/components/controls/FavoriteBaseStateless.tsx51
-rw-r--r--server/sonar-web/src/main/js/components/controls/FavoriteContainer.ts58
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBaseStateless-test.tsx53
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBaseStateless-test.tsx.snap13
-rw-r--r--server/sonar-web/src/main/js/components/workspace/__tests__/__snapshots__/WorkspaceComponentViewer-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/store/favorites/duck.ts81
-rw-r--r--server/sonar-web/src/main/js/store/rootReducer.js5
16 files changed, 195 insertions, 508 deletions
diff --git a/server/sonar-web/src/main/js/api/components.ts b/server/sonar-web/src/main/js/api/components.ts
index 899e6a1c450..671fb298cbf 100644
--- a/server/sonar-web/src/main/js/api/components.ts
+++ b/server/sonar-web/src/main/js/api/components.ts
@@ -26,7 +26,8 @@ import {
MyProject,
Metric,
ComponentMeasure,
- LightComponent
+ LightComponent,
+ SourceViewerFile
} from '../app/types';
export interface BaseSearchProjectsParameters {
@@ -287,7 +288,7 @@ export function getSuggestions(
export function getComponentForSourceViewer(
data: { component: string } & BranchParameters
-): Promise<any> {
+): Promise<SourceViewerFile> {
return getJSON('/api/components/app', data);
}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts b/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts
index e86d1d372d2..36abc33bb09 100644
--- a/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts
+++ b/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts
@@ -27,7 +27,7 @@ import * as request from '../../../helpers/request';
import DateFromNow from '../../../components/intl/DateFromNow';
import DateFormatter from '../../../components/intl/DateFormatter';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
-import FavoriteContainer from '../../../components/controls/FavoriteContainer';
+import Favorite from '../../../components/controls/Favorite';
import HomePageSelect from '../../../components/controls/HomePageSelect';
import ListFooter from '../../../components/controls/ListFooter';
import Modal from '../../../components/controls/Modal';
@@ -86,7 +86,7 @@ const exposeLibraries = () => {
DropdownIcon,
DuplicationsRating,
EditButton,
- FavoriteContainer,
+ Favorite,
HelpIcon,
HelpTooltip,
HomePageSelect,
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureFavoriteContainer.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureFavoriteContainer.js
deleted file mode 100644
index 627913abc1c..00000000000
--- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureFavoriteContainer.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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.
- */
-// @flow
-import React from 'react';
-import { connect } from 'react-redux';
-import FavoriteContainer from '../../../components/controls/FavoriteContainer';
-import { getComponentForSourceViewer } from '../../../api/components';
-import { receiveFavorites } from '../../../store/favorites/duck';
-import { isMainBranch } from '../../../helpers/branches';
-
-/*:: type FavComponent = { key: string, canMarkAsFavorite: boolean, fav: boolean }; */
-
-/*:: type Props = {
- branchLike?: { id?: string; name: string },
- className?: string,
- component: string,
- onReceiveComponent: (component: FavComponent) => void
-}; */
-
-/*:: type State = { component: ?FavComponent }; */
-
-class MeasureFavoriteContainer extends React.PureComponent {
- /*:: mounted: boolean; */
- /*:: props: Props; */
- state /*: State */ = {
- component: null
- };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchComponentFavorite(this.props);
- }
-
- componentWillReceiveProps(nextProps /*: Props */) {
- if (nextProps.component !== this.props.component) {
- this.fetchComponentFavorite(nextProps);
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchComponentFavorite({ component, onReceiveComponent } /*: Props */) {
- getComponentForSourceViewer({ component }).then(component => {
- this.setState({ component });
- onReceiveComponent(component);
- });
- }
-
- render() {
- const { component } = this.state;
- if (
- component == null ||
- !component.canMarkAsFavorite ||
- (this.props.branchLike && !isMainBranch(this.props.branchLike))
- ) {
- return null;
- }
- return (
- <FavoriteContainer className={this.props.className} componentKey={this.props.component} />
- );
- }
-}
-
-const mapStateToProps = null;
-
-const mapDispatchToProps = {
- onReceiveComponent: (component /*: FavComponent */) => dispatch => {
- if (component.canMarkAsFavorite) {
- const favorites = [];
- const notFavorites = [];
- if (component.fav) {
- favorites.push({ key: component.key });
- } else {
- notFavorites.push({ key: component.key });
- }
- dispatch(receiveFavorites(favorites, notFavorites));
- }
- }
-};
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(MeasureFavoriteContainer);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureFavoriteContainer.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureFavoriteContainer.tsx
new file mode 100644
index 00000000000..d062ad6af50
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureFavoriteContainer.tsx
@@ -0,0 +1,86 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 Favorite from '../../../components/controls/Favorite';
+import { getComponentForSourceViewer } from '../../../api/components';
+import { isMainBranch } from '../../../helpers/branches';
+import { BranchLike, SourceViewerFile } from '../../../app/types';
+
+type FavComponent = Pick<SourceViewerFile, 'canMarkAsFavorite' | 'fav' | 'key' | 'q'>;
+
+interface Props {
+ branchLike?: BranchLike;
+ className?: string;
+ component: string;
+}
+
+interface State {
+ component?: FavComponent;
+}
+
+export default class MeasureFavoriteContainer extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = {};
+
+ componentDidMount() {
+ this.mounted = true;
+ this.fetchComponentFavorite();
+ }
+
+ componentDidUpdate(prevProps: Props) {
+ if (prevProps.component !== this.props.component) {
+ this.fetchComponentFavorite();
+ }
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ fetchComponentFavorite() {
+ getComponentForSourceViewer({ component: this.props.component }).then(
+ component => {
+ if (this.mounted) {
+ this.setState({ component });
+ }
+ },
+ () => {}
+ );
+ }
+
+ render() {
+ const { component } = this.state;
+ if (
+ !component ||
+ !component.canMarkAsFavorite ||
+ (this.props.branchLike && !isMainBranch(this.props.branchLike))
+ ) {
+ return null;
+ }
+ return (
+ <Favorite
+ className={this.props.className}
+ component={component.key}
+ favorite={component.fav || false}
+ qualifier={component.q}
+ />
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/component/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/component/components/__tests__/__snapshots__/App-test.tsx.snap
index c513d6b7a6d..80a0c87199c 100644
--- a/server/sonar-web/src/main/js/apps/component/components/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/component/components/__tests__/__snapshots__/App-test.tsx.snap
@@ -4,7 +4,7 @@ exports[`renders 1`] = `
<div
className="page page-limited"
>
- <Connect(LazyLoader)
+ <LazyLoader
aroundLine={7}
branchLike={
Object {
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx
index 5e6a563abf2..f322716526a 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx
+++ b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx
@@ -17,37 +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 { Dispatch } from 'redux';
-import { connect, Omit } from 'react-redux';
-import { Props } from './SourceViewerBase';
import { lazyLoad } from '../lazyLoad';
-import { SourceViewerFile } from '../../app/types';
-import { receiveFavorites } from '../../store/favorites/duck';
-const mapStateToProps = null;
-
-interface DispatchProps {
- onReceiveComponent: (component: SourceViewerFile) => void;
-}
-
-const onReceiveComponent = (component: SourceViewerFile) => (dispatch: Dispatch<any>) => {
- if (component.canMarkAsFavorite) {
- const favorites = [];
- const notFavorites = [];
- if (component.fav) {
- favorites.push({ key: component.key });
- } else {
- notFavorites.push({ key: component.key });
- }
- dispatch(receiveFavorites(favorites, notFavorites));
- }
-};
-
-const mapDispatchToProps: DispatchProps = { onReceiveComponent };
-
-type OwnProps = Omit<Props, keyof DispatchProps>;
-
-export default connect<null, DispatchProps, OwnProps>(
- mapStateToProps,
- mapDispatchToProps
-)(lazyLoad(() => import(/* webpackPrefetch: true */ './SourceViewerBase')));
+const SourceViewer = lazyLoad(() => import(/* webpackPrefetch: true */ './SourceViewerBase'));
+export default SourceViewer;
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx
index c403c76d948..6ea9df12ea0 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx
+++ b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx
@@ -67,17 +67,17 @@ export interface Props {
// but kept to maintaint the location indexes
highlightedLocations?: (FlowLocation | undefined)[];
highlightedLocationMessage?: { index: number; text: string | undefined };
- loadComponent?: (
+ loadComponent: (
component: string,
branchLike: BranchLike | undefined
) => Promise<SourceViewerFile>;
- loadIssues?: (
+ loadIssues: (
component: string,
from: number,
to: number,
branchLike: BranchLike | undefined
) => Promise<Issue[]>;
- loadSources?: (
+ loadSources: (
component: string,
from: number,
to: number,
@@ -88,7 +88,6 @@ export interface Props {
onIssueChange?: (issue: Issue) => void;
onIssueSelect?: (issueKey: string) => void;
onIssueUnselect?: () => void;
- onReceiveComponent: (component: SourceViewerFile) => void;
scroll?: (element: HTMLElement) => void;
selectedIssue?: string;
}
@@ -128,7 +127,10 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
displayAllIssues: false,
displayIssueLocationsCount: true,
displayIssueLocationsLink: true,
- displayLocationMarkers: true
+ displayLocationMarkers: true,
+ loadComponent: defaultLoadComponent,
+ loadIssues: defaultLoadIssues,
+ loadSources: defaultLoadSources
};
constructor(props: Props) {
@@ -204,21 +206,6 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
this.mounted = false;
}
- // react typings do not take `defaultProps` into account,
- // so use these getters to get type-safe methods
-
- get safeLoadComponent() {
- return this.props.loadComponent || defaultLoadComponent;
- }
-
- get safeLoadIssues() {
- return this.props.loadIssues || defaultLoadIssues;
- }
-
- get safeLoadSources() {
- return this.props.loadSources || defaultLoadSources;
- }
-
computeCoverageStatus(lines: SourceLine[]) {
return lines.map(line => ({ ...line, coverageStatus: getCoverageStatus(line) }));
}
@@ -237,7 +224,7 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
fetchComponent() {
this.setState({ loading: true });
const loadIssues = (component: SourceViewerFile, sources: SourceLine[]) => {
- this.safeLoadIssues(this.props.component, 1, LINES, this.props.branchLike).then(
+ this.props.loadIssues(this.props.component, 1, LINES, this.props.branchLike).then(
issues => {
if (this.mounted) {
const finalSources = sources.slice(0, LINES);
@@ -301,7 +288,6 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
};
const onResolve = (component: SourceViewerFile) => {
- this.props.onReceiveComponent(component);
const sourcesRequest =
component.q === 'FIL' || component.q === 'UTS' ? this.loadSources() : Promise.resolve([]);
sourcesRequest.then(
@@ -310,10 +296,9 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
);
};
- this.safeLoadComponent(this.props.component, this.props.branchLike).then(
- onResolve,
- onFailLoadComponent
- );
+ this.props
+ .loadComponent(this.props.component, this.props.branchLike)
+ .then(onResolve, onFailLoadComponent);
}
fetchSources() {
@@ -346,25 +331,27 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
}
const firstSourceLine = this.state.sources[0];
const lastSourceLine = this.state.sources[this.state.sources.length - 1];
- this.safeLoadIssues(
- this.props.component,
- firstSourceLine && firstSourceLine.line,
- lastSourceLine && lastSourceLine.line,
- this.props.branchLike
- ).then(
- issues => {
- if (this.mounted) {
- this.setState({
- issues,
- issuesByLine: issuesByLine(issues),
- issueLocationsByLine: locationsByLine(issues)
- });
+ this.props
+ .loadIssues(
+ this.props.component,
+ firstSourceLine && firstSourceLine.line,
+ lastSourceLine && lastSourceLine.line,
+ this.props.branchLike
+ )
+ .then(
+ issues => {
+ if (this.mounted) {
+ this.setState({
+ issues,
+ issuesByLine: issuesByLine(issues),
+ issueLocationsByLine: locationsByLine(issues)
+ });
+ }
+ },
+ () => {
+ // TODO
}
- },
- () => {
- // TODO
- }
- );
+ );
}
loadSources = (): Promise<SourceLine[]> => {
@@ -390,10 +377,9 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
// request one additional line to define `hasSourcesAfter`
to++;
- return this.safeLoadSources(this.props.component, from, to, this.props.branchLike).then(
- sources => resolve(sources),
- onFailLoadSources
- );
+ return this.props
+ .loadSources(this.props.component, from, to, this.props.branchLike)
+ .then(sources => resolve(sources), onFailLoadSources);
});
};
@@ -404,46 +390,43 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
const firstSourceLine = this.state.sources[0];
this.setState({ loadingSourcesBefore: true });
const from = Math.max(1, firstSourceLine.line - LINES);
- this.safeLoadSources(
- this.props.component,
- from,
- firstSourceLine.line - 1,
- this.props.branchLike
- ).then(
- sources => {
- this.safeLoadIssues(
- this.props.component,
- from,
- firstSourceLine.line - 1,
- this.props.branchLike
- ).then(
- issues => {
- if (this.mounted) {
- this.setState(prevState => {
- const nextIssues = uniqBy(
- [...issues, ...(prevState.issues || [])],
- issue => issue.key
- );
- return {
- issues: nextIssues,
- issuesByLine: issuesByLine(nextIssues),
- issueLocationsByLine: locationsByLine(nextIssues),
- loadingSourcesBefore: false,
- sources: [...this.computeCoverageStatus(sources), ...(prevState.sources || [])],
- symbolsByLine: { ...prevState.symbolsByLine, ...symbolsByLine(sources) }
- };
- });
- }
- },
- () => {
- // TODO
- }
- );
- },
- () => {
- // TODO
- }
- );
+ this.props
+ .loadSources(this.props.component, from, firstSourceLine.line - 1, this.props.branchLike)
+ .then(
+ sources => {
+ this.props
+ .loadIssues(this.props.component, from, firstSourceLine.line - 1, this.props.branchLike)
+ .then(
+ issues => {
+ if (this.mounted) {
+ this.setState(prevState => {
+ const nextIssues = uniqBy(
+ [...issues, ...(prevState.issues || [])],
+ issue => issue.key
+ );
+ return {
+ issues: nextIssues,
+ issuesByLine: issuesByLine(nextIssues),
+ issueLocationsByLine: locationsByLine(nextIssues),
+ loadingSourcesBefore: false,
+ sources: [
+ ...this.computeCoverageStatus(sources),
+ ...(prevState.sources || [])
+ ],
+ symbolsByLine: { ...prevState.symbolsByLine, ...symbolsByLine(sources) }
+ };
+ });
+ }
+ },
+ () => {
+ // TODO
+ }
+ );
+ },
+ () => {
+ // TODO
+ }
+ );
};
loadSourcesAfter = () => {
@@ -455,9 +438,9 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
const fromLine = lastSourceLine.line + 1;
// request one additional line to define `hasSourcesAfter`
const toLine = lastSourceLine.line + LINES + 1;
- this.safeLoadSources(this.props.component, fromLine, toLine, this.props.branchLike).then(
+ this.props.loadSources(this.props.component, fromLine, toLine, this.props.branchLike).then(
sources => {
- this.safeLoadIssues(this.props.component, fromLine, toLine, this.props.branchLike).then(
+ this.props.loadIssues(this.props.component, fromLine, toLine, this.props.branchLike).then(
issues => {
if (this.mounted) {
this.setState(prevState => {
@@ -749,13 +732,13 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
}
}
-function defaultLoadComponent(key: string, branchLike: BranchLike | undefined) {
+function defaultLoadComponent(component: string, branchLike: BranchLike | undefined) {
return Promise.all([
- getComponentForSourceViewer({ component: key, ...getBranchLikeQuery(branchLike) }),
- getComponentData({ component: key, ...getBranchLikeQuery(branchLike) })
+ getComponentForSourceViewer({ component, ...getBranchLikeQuery(branchLike) }),
+ getComponentData({ component, ...getBranchLikeQuery(branchLike) })
]).then(([component, data]) => ({
...component,
- leakPeriodDate: data.leakPeriodDate && parseDate(data.leakPeriodDate)
+ leakPeriodDate: data.leakPeriodDate
}));
}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx
index 80ce4ba53d2..36595d01856 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx
+++ b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx
@@ -25,7 +25,7 @@ import MeasuresOverlay from './components/MeasuresOverlay';
import { SourceViewerFile, BranchLike } from '../../app/types';
import QualifierIcon from '../icons-components/QualifierIcon';
import Dropdown from '../controls/Dropdown';
-import FavoriteContainer from '../controls/FavoriteContainer';
+import Favorite from '../controls/Favorite';
import ListIcon from '../icons-components/ListIcon';
import { ButtonIcon } from '../ui/buttons';
import { PopupPlacement } from '../ui/popups';
@@ -122,7 +122,12 @@ export default class SourceViewerHeader extends React.PureComponent<Props, State
<span className="component-name-file">{fileFromPath(path)}</span>
{this.props.sourceViewerFile.canMarkAsFavorite &&
(!this.props.branchLike || isMainBranch(this.props.branchLike)) && (
- <FavoriteContainer className="component-name-favorite" componentKey={key} />
+ <Favorite
+ className="component-name-favorite"
+ component={key}
+ favorite={this.props.sourceViewerFile.fav || false}
+ qualifier={this.props.sourceViewerFile.q}
+ />
)}
</div>
</div>
diff --git a/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx b/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx
index a1bd2cc6866..4dbd3b05cea 100644
--- a/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx
+++ b/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx
@@ -67,19 +67,25 @@ export default class FavoriteBase extends React.PureComponent<Props, State> {
};
addFavorite() {
- this.props.addFavorite().then(() => {
- if (this.mounted) {
- this.setState({ favorite: true });
- }
- });
+ this.props.addFavorite().then(
+ () => {
+ if (this.mounted) {
+ this.setState({ favorite: true });
+ }
+ },
+ () => {}
+ );
}
removeFavorite() {
- this.props.removeFavorite().then(() => {
- if (this.mounted) {
- this.setState({ favorite: false });
- }
- });
+ this.props.removeFavorite().then(
+ () => {
+ if (this.mounted) {
+ this.setState({ favorite: false });
+ }
+ },
+ () => {}
+ );
}
render() {
diff --git a/server/sonar-web/src/main/js/components/controls/FavoriteBaseStateless.tsx b/server/sonar-web/src/main/js/components/controls/FavoriteBaseStateless.tsx
deleted file mode 100644
index 544056d50b6..00000000000
--- a/server/sonar-web/src/main/js/components/controls/FavoriteBaseStateless.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 * as classNames from 'classnames';
-import FavoriteIcon from '../icons-components/FavoriteIcon';
-
-interface Props {
- addFavorite: () => void;
- className?: string;
- favorite: boolean;
- removeFavorite: () => void;
-}
-
-export default class FavoriteBaseStateless extends React.PureComponent<Props> {
- toggleFavorite = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- if (this.props.favorite) {
- this.props.removeFavorite();
- } else {
- this.props.addFavorite();
- }
- };
-
- render() {
- return (
- <a
- className={classNames('link-no-underline', this.props.className)}
- href="#"
- onClick={this.toggleFavorite}>
- <FavoriteIcon favorite={this.props.favorite} />
- </a>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/FavoriteContainer.ts b/server/sonar-web/src/main/js/components/controls/FavoriteContainer.ts
deleted file mode 100644
index 8d9da47f1a3..00000000000
--- a/server/sonar-web/src/main/js/components/controls/FavoriteContainer.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 { connect } from 'react-redux';
-import FavoriteBaseStateless from './FavoriteBaseStateless';
-import { isFavorite } from '../../store/rootReducer';
-import * as actionCreators from '../../store/favorites/duck';
-import * as api from '../../api/favorites';
-import { addGlobalErrorMessage } from '../../store/globalMessages/duck';
-import { parseError } from '../../helpers/request';
-
-const addFavorite = (componentKey: string) => (dispatch: Function) => {
- // optimistic update
- dispatch(actionCreators.addFavorite(componentKey));
- api.addFavorite(componentKey).catch(error => {
- dispatch(actionCreators.removeFavorite(componentKey));
- parseError(error).then(message => dispatch(addGlobalErrorMessage(message)));
- });
-};
-
-const removeFavorite = (componentKey: string) => (dispatch: Function) => {
- // optimistic update
- dispatch(actionCreators.removeFavorite(componentKey));
- api.removeFavorite(componentKey).catch(error => {
- dispatch(actionCreators.addFavorite(componentKey));
- parseError(error).then(message => dispatch(addGlobalErrorMessage(message)));
- });
-};
-
-const mapStateToProps = (state: any, ownProps: any) => ({
- favorite: isFavorite(state, ownProps.componentKey)
-});
-
-const mapDispatchToProps = (dispatch: Function, ownProps: any) => ({
- addFavorite: () => dispatch(addFavorite(ownProps.componentKey)),
- removeFavorite: () => dispatch(removeFavorite(ownProps.componentKey))
-});
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(FavoriteBaseStateless);
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBaseStateless-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBaseStateless-test.tsx
deleted file mode 100644
index 2ed0bd154a2..00000000000
--- a/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBaseStateless-test.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 { shallow } from 'enzyme';
-import FavoriteBaseStateless from '../FavoriteBaseStateless';
-import { click } from '../../../helpers/testUtils';
-
-it('renders', () => {
- expect(
- shallow(
- <FavoriteBaseStateless addFavorite={jest.fn()} favorite={true} removeFavorite={jest.fn()} />
- )
- ).toMatchSnapshot();
-});
-
-it('adds favorite', () => {
- const addFavorite = jest.fn();
- const wrapper = shallow(
- <FavoriteBaseStateless addFavorite={addFavorite} favorite={false} removeFavorite={jest.fn()} />
- );
- click(wrapper);
- expect(addFavorite).toBeCalled();
-});
-
-it('removes favorite', () => {
- const removeFavorite = jest.fn();
- const wrapper = shallow(
- <FavoriteBaseStateless
- addFavorite={jest.fn()}
- favorite={true}
- removeFavorite={removeFavorite}
- />
- );
- click(wrapper);
- expect(removeFavorite).toBeCalled();
-});
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBaseStateless-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBaseStateless-test.tsx.snap
deleted file mode 100644
index 9edbec0cb0f..00000000000
--- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBaseStateless-test.tsx.snap
+++ /dev/null
@@ -1,13 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<a
- className="link-no-underline"
- href="#"
- onClick={[Function]}
->
- <FavoriteIcon
- favorite={true}
- />
-</a>
-`;
diff --git a/server/sonar-web/src/main/js/components/workspace/__tests__/__snapshots__/WorkspaceComponentViewer-test.tsx.snap b/server/sonar-web/src/main/js/components/workspace/__tests__/__snapshots__/WorkspaceComponentViewer-test.tsx.snap
index 7453ffec082..fb3201016c1 100644
--- a/server/sonar-web/src/main/js/components/workspace/__tests__/__snapshots__/WorkspaceComponentViewer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/workspace/__tests__/__snapshots__/WorkspaceComponentViewer-test.tsx.snap
@@ -28,7 +28,7 @@ exports[`should render 1`] = `
}
}
>
- <Connect(LazyLoader)
+ <LazyLoader
component="foo"
onLoaded={[Function]}
/>
diff --git a/server/sonar-web/src/main/js/store/favorites/duck.ts b/server/sonar-web/src/main/js/store/favorites/duck.ts
deleted file mode 100644
index 710151e4eb2..00000000000
--- a/server/sonar-web/src/main/js/store/favorites/duck.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 { uniq, without } from 'lodash';
-
-interface Favorite {
- key: string;
-}
-
-interface ReceiveFavoritesAction {
- type: 'RECEIVE_FAVORITES';
- favorites: Array<Favorite>;
- notFavorites: Array<Favorite>;
-}
-
-interface AddFavoriteAction {
- type: 'ADD_FAVORITE';
- componentKey: string;
-}
-
-interface RemoveFavoriteAction {
- type: 'REMOVE_FAVORITE';
- componentKey: string;
-}
-
-type Action = ReceiveFavoritesAction | AddFavoriteAction | RemoveFavoriteAction;
-
-type State = string[];
-
-export function receiveFavorites(
- favorites: Favorite[],
- notFavorites: Favorite[] = []
-): ReceiveFavoritesAction {
- return { type: 'RECEIVE_FAVORITES', favorites, notFavorites };
-}
-
-export function addFavorite(componentKey: string): AddFavoriteAction {
- return { type: 'ADD_FAVORITE', componentKey };
-}
-
-export function removeFavorite(componentKey: string): RemoveFavoriteAction {
- return { type: 'REMOVE_FAVORITE', componentKey };
-}
-
-export default function(state: State = [], action: Action): State {
- if (action.type === 'RECEIVE_FAVORITES') {
- const toAdd = action.favorites.map(f => f.key);
- const toRemove = action.notFavorites.map(f => f.key);
- return without(uniq([...state, ...toAdd]), ...toRemove);
- }
-
- if (action.type === 'ADD_FAVORITE') {
- return uniq([...state, action.componentKey]);
- }
-
- if (action.type === 'REMOVE_FAVORITE') {
- return without(state, action.componentKey);
- }
-
- return state;
-}
-
-export function isFavorite(state: State, componentKey: string) {
- return state.includes(componentKey);
-}
diff --git a/server/sonar-web/src/main/js/store/rootReducer.js b/server/sonar-web/src/main/js/store/rootReducer.js
index 73c0dc340a1..21e8c828500 100644
--- a/server/sonar-web/src/main/js/store/rootReducer.js
+++ b/server/sonar-web/src/main/js/store/rootReducer.js
@@ -20,7 +20,6 @@
import { combineReducers } from 'redux';
import appState from './appState/duck';
import users, * as fromUsers from './users/reducer';
-import favorites, * as fromFavorites from './favorites/duck';
import languages, * as fromLanguages from './languages/reducer';
import metrics, * as fromMetrics from './metrics/reducer';
import organizations, * as fromOrganizations from './organizations/duck';
@@ -33,7 +32,6 @@ import settingsApp, * as fromSettingsApp from '../apps/settings/store/rootReduce
export default combineReducers({
appState,
globalMessages,
- favorites,
languages,
metrics,
organizations,
@@ -66,9 +64,6 @@ export const getUsersByLogins = (state, logins) => fromUsers.getUsersByLogins(st
export const getUsers = state => fromUsers.getUsers(state.users);
-export const isFavorite = (state, componentKey) =>
- fromFavorites.isFavorite(state.favorites, componentKey);
-
export const getMarketplaceState = state => state.marketplace;
export const getMetrics = state => fromMetrics.getMetrics(state.metrics);