diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2018-09-03 09:21:22 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2018-09-03 20:20:51 +0200 |
commit | f6fd6fb056ca6c3de3637cfeafb53c30815ee12d (patch) | |
tree | bdf6b3a660066ffe6aaf644f6969e4353a7e21c8 /server/sonar-web/src/main/js | |
parent | f332f24ea986de3267aedcc9ba8ec1441ff4226b (diff) | |
download | sonarqube-f6fd6fb056ca6c3de3637cfeafb53c30815ee12d.tar.gz sonarqube-f6fd6fb056ca6c3de3637cfeafb53c30815ee12d.zip |
finish typing redux store and simplify connected components (#675)
Diffstat (limited to 'server/sonar-web/src/main/js')
178 files changed, 1221 insertions, 1356 deletions
diff --git a/server/sonar-web/src/main/js/api/issues.ts b/server/sonar-web/src/main/js/api/issues.ts index 6f1e4ed20e0..40d1222314a 100644 --- a/server/sonar-web/src/main/js/api/issues.ts +++ b/server/sonar-web/src/main/js/api/issues.ts @@ -110,7 +110,7 @@ export function searchIssueTags(data: { } export function getIssueChangelog(issue: string): Promise<any> { - return getJSON('/api/issues/changelog', { issue }).then(r => r.changelog); + return getJSON('/api/issues/changelog', { issue }).then(r => r.changelog, throwGlobalError); } export function getIssueFilters() { diff --git a/server/sonar-web/src/main/js/api/languages.ts b/server/sonar-web/src/main/js/api/languages.ts index f5902cdb77b..c49c1290672 100644 --- a/server/sonar-web/src/main/js/api/languages.ts +++ b/server/sonar-web/src/main/js/api/languages.ts @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { getJSON } from '../helpers/request'; +import throwGlobalError from '../app/utils/throwGlobalError'; export interface Language { key: string; @@ -25,5 +26,5 @@ export interface Language { } export function getLanguages(): Promise<Language[]> { - return getJSON('/api/languages/list').then(r => r.languages); + return getJSON('/api/languages/list').then(r => r.languages, throwGlobalError); } diff --git a/server/sonar-web/src/main/js/api/organizations.ts b/server/sonar-web/src/main/js/api/organizations.ts index 78d8f63ac1c..289d6ce99d5 100644 --- a/server/sonar-web/src/main/js/api/organizations.ts +++ b/server/sonar-web/src/main/js/api/organizations.ts @@ -28,7 +28,7 @@ export function getOrganizations(data: { organizations: Organization[]; paging: Paging; }> { - return getJSON('/api/organizations/search', data); + return getJSON('/api/organizations/search', data).catch(throwGlobalError); } export function getOrganization(key: string): Promise<Organization | undefined> { @@ -48,18 +48,21 @@ interface GetOrganizationNavigation { } export function getOrganizationNavigation(key: string): Promise<GetOrganizationNavigation> { - return getJSON('/api/navigation/organization', { organization: key }).then(r => r.organization); + return getJSON('/api/navigation/organization', { organization: key }).then( + r => r.organization, + throwGlobalError + ); } export function createOrganization(data: OrganizationBase): Promise<Organization> { return postJSON('/api/organizations/create', data).then(r => r.organization, throwGlobalError); } -export function updateOrganization(key: string, changes: OrganizationBase): Promise<void> { - return post('/api/organizations/update', { key, ...changes }); +export function updateOrganization(key: string, changes: OrganizationBase) { + return post('/api/organizations/update', { key, ...changes }).catch(throwGlobalError); } -export function deleteOrganization(key: string): Promise<void | Response> { +export function deleteOrganization(key: string) { return post('/api/organizations/delete', { key }).catch(throwGlobalError); } diff --git a/server/sonar-web/src/main/js/api/permissions.ts b/server/sonar-web/src/main/js/api/permissions.ts index e14367bb6a7..116e242e3c2 100644 --- a/server/sonar-web/src/main/js/api/permissions.ts +++ b/server/sonar-web/src/main/js/api/permissions.ts @@ -29,7 +29,7 @@ export function grantPermissionToUser( login: string, permission: string, organization?: string -): Promise<void> { +) { const data: RequestData = { login, permission }; if (projectKey) { data.projectKey = projectKey; @@ -37,7 +37,7 @@ export function grantPermissionToUser( if (organization && !projectKey) { data.organization = organization; } - return post('/api/permissions/add_user', data); + return post('/api/permissions/add_user', data).catch(throwGlobalError); } export function revokePermissionFromUser( @@ -45,7 +45,7 @@ export function revokePermissionFromUser( login: string, permission: string, organization?: string -): Promise<void> { +) { const data: RequestData = { login, permission }; if (projectKey) { data.projectKey = projectKey; @@ -53,7 +53,7 @@ export function revokePermissionFromUser( if (organization && !projectKey) { data.organization = organization; } - return post('/api/permissions/remove_user', data); + return post('/api/permissions/remove_user', data).catch(throwGlobalError); } export function grantPermissionToGroup( @@ -61,7 +61,7 @@ export function grantPermissionToGroup( groupName: string, permission: string, organization?: string -): Promise<void> { +) { const data: RequestData = { groupName, permission }; if (projectKey) { data.projectKey = projectKey; @@ -69,7 +69,7 @@ export function grantPermissionToGroup( if (organization) { data.organization = organization; } - return post('/api/permissions/add_group', data); + return post('/api/permissions/add_group', data).catch(throwGlobalError); } export function revokePermissionFromGroup( @@ -77,7 +77,7 @@ export function revokePermissionFromGroup( groupName: string, permission: string, organization?: string -): Promise<void> { +) { const data: RequestData = { groupName, permission }; if (projectKey) { data.projectKey = projectKey; @@ -85,7 +85,7 @@ export function revokePermissionFromGroup( if (organization) { data.organization = organization; } - return post('/api/permissions/remove_group', data); + return post('/api/permissions/remove_group', data).catch(throwGlobalError); } interface GetPermissionTemplatesResponse { diff --git a/server/sonar-web/src/main/js/api/quality-profiles.ts b/server/sonar-web/src/main/js/api/quality-profiles.ts index bf8fc2b3eeb..93e0c1d5064 100644 --- a/server/sonar-web/src/main/js/api/quality-profiles.ts +++ b/server/sonar-web/src/main/js/api/quality-profiles.ts @@ -95,7 +95,8 @@ export function createQualityProfile(data: RequestData): Promise<any> { .setData(data) .submit() .then(checkStatus) - .then(parseJSON); + .then(parseJSON) + .catch(throwGlobalError); } export function restoreQualityProfile(data: RequestData): Promise<any> { @@ -104,7 +105,8 @@ export function restoreQualityProfile(data: RequestData): Promise<any> { .setData(data) .submit() .then(checkStatus) - .then(parseJSON); + .then(parseJSON) + .catch(throwGlobalError); } export interface ProfileProject { @@ -128,20 +130,22 @@ export function setDefaultProfile(profileKey: string): Promise<void> { return post('/api/qualityprofiles/set_default', { profileKey }); } -export function renameProfile(key: string, name: string): Promise<void> { - return post('/api/qualityprofiles/rename', { key, name }); +export function renameProfile(key: string, name: string) { + return post('/api/qualityprofiles/rename', { key, name }).catch(throwGlobalError); } export function copyProfile(fromKey: string, toName: string): Promise<any> { - return postJSON('/api/qualityprofiles/copy', { fromKey, toName }); + return postJSON('/api/qualityprofiles/copy', { fromKey, toName }).catch(throwGlobalError); } -export function deleteProfile(profileKey: string): Promise<void> { - return post('/api/qualityprofiles/delete', { profileKey }); +export function deleteProfile(profileKey: string) { + return post('/api/qualityprofiles/delete', { profileKey }).catch(throwGlobalError); } -export function changeProfileParent(profileKey: string, parentKey: string): Promise<void> { - return post('/api/qualityprofiles/change_parent', { profileKey, parentKey }); +export function changeProfileParent(profileKey: string, parentKey: string) { + return post('/api/qualityprofiles/change_parent', { profileKey, parentKey }).catch( + throwGlobalError + ); } export function getImporters(): Promise< diff --git a/server/sonar-web/src/main/js/app/components/AdminContainer.tsx b/server/sonar-web/src/main/js/app/components/AdminContainer.tsx index 05c330a371f..cb2d5b99709 100644 --- a/server/sonar-web/src/main/js/app/components/AdminContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/AdminContainer.tsx @@ -23,9 +23,9 @@ import Helmet from 'react-helmet'; import { connect } from 'react-redux'; import MarketplaceContext, { defaultPendingPlugins } from './MarketplaceContext'; import SettingsNav from './nav/settings/SettingsNav'; -import { getAppState } from '../../store/rootReducer'; +import { getAppState, Store } from '../../store/rootReducer'; import { getSettingsNavigation } from '../../api/nav'; -import { setAdminPages } from '../../store/appState/duck'; +import { setAdminPages } from '../../store/appState'; import { translate } from '../../helpers/l10n'; import { Extension, AppState } from '../types'; import { PluginPendingResult, getPendingPlugins } from '../../api/plugins'; @@ -121,7 +121,7 @@ class AdminContainer extends React.PureComponent<Props, State> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ appState: getAppState(state) }); @@ -129,7 +129,7 @@ const mapDispatchToProps: DispatchToProps = { setAdminPages }; -export default connect<StateProps, DispatchToProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(AdminContainer); diff --git a/server/sonar-web/src/main/js/app/components/App.tsx b/server/sonar-web/src/main/js/app/components/App.tsx index 22cd429689a..e5257a4a171 100644 --- a/server/sonar-web/src/main/js/app/components/App.tsx +++ b/server/sonar-web/src/main/js/app/components/App.tsx @@ -26,7 +26,7 @@ import { fetchLanguages } from '../../store/rootActions'; import { fetchMyOrganizations } from '../../apps/account/organizations/actions'; import { getInstance, isSonarCloud } from '../../helpers/system'; import { lazyLoad } from '../../components/lazyLoad'; -import { getCurrentUser, getAppState, getGlobalSettingValue } from '../../store/rootReducer'; +import { getCurrentUser, getAppState, getGlobalSettingValue, Store } from '../../store/rootReducer'; const PageTracker = lazyLoad(() => import('./PageTracker')); @@ -104,7 +104,7 @@ class App extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ appState: getAppState(state), currentUser: getCurrentUser(state), enableGravatar: (getGlobalSettingValue(state, 'sonar.lf.enableGravatar') || {}).value === 'true', diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx index 00e376c5dfc..e8ee249706d 100644 --- a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx @@ -315,7 +315,7 @@ export class ComponentContainer extends React.PureComponent<Props, State> { const mapDispatchToProps = { fetchOrganizations }; -export default connect<any, any, any>( +export default connect( null, mapDispatchToProps )(ComponentContainer); diff --git a/server/sonar-web/src/main/js/app/components/GlobalFooterContainer.tsx b/server/sonar-web/src/main/js/app/components/GlobalFooterContainer.tsx index 4f079504d72..158478034d5 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalFooterContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalFooterContainer.tsx @@ -19,7 +19,7 @@ */ import { connect } from 'react-redux'; import GlobalFooter from './GlobalFooter'; -import { getAppState } from '../../store/rootReducer'; +import { getAppState, Store } from '../../store/rootReducer'; import { EditionKey } from '../../apps/marketplace/utils'; interface StateProps { @@ -28,14 +28,10 @@ interface StateProps { sonarqubeVersion?: string; } -interface OwnProps { - hideLoggedInInfo?: boolean; -} - -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ productionDatabase: getAppState(state).productionDatabase, sonarqubeEdition: getAppState(state).edition, sonarqubeVersion: getAppState(state).version }); -export default connect<StateProps, {}, OwnProps>(mapStateToProps)(GlobalFooter); +export default connect(mapStateToProps)(GlobalFooter); diff --git a/server/sonar-web/src/main/js/app/components/GlobalMessagesContainer.tsx b/server/sonar-web/src/main/js/app/components/GlobalMessagesContainer.tsx index d8366702bc8..e9dfd8a6e08 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalMessagesContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalMessagesContainer.tsx @@ -19,10 +19,10 @@ */ import { connect } from 'react-redux'; import GlobalMessages from '../../components/controls/GlobalMessages'; -import { getGlobalMessages } from '../../store/rootReducer'; -import { closeGlobalMessage } from '../../store/globalMessages/duck'; +import { getGlobalMessages, Store } from '../../store/rootReducer'; +import { closeGlobalMessage } from '../../store/globalMessages'; -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ messages: getGlobalMessages(state) }); diff --git a/server/sonar-web/src/main/js/app/components/Landing.tsx b/server/sonar-web/src/main/js/app/components/Landing.tsx index d4f80be9ab8..f96be5fc011 100644 --- a/server/sonar-web/src/main/js/app/components/Landing.tsx +++ b/server/sonar-web/src/main/js/app/components/Landing.tsx @@ -22,7 +22,7 @@ import * as PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { Location } from 'history'; import { CurrentUser, isLoggedIn } from '../types'; -import { getCurrentUser } from '../../store/rootReducer'; +import { getCurrentUser, Store } from '../../store/rootReducer'; import { getHomePageUrl } from '../../helpers/urls'; interface StateProps { @@ -57,8 +57,8 @@ class Landing extends React.PureComponent<StateProps & OwnProps> { } } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ currentUser: getCurrentUser(state) }); -export default connect<StateProps, {}, OwnProps>(mapStateToProps)(Landing); +export default connect(mapStateToProps)(Landing); diff --git a/server/sonar-web/src/main/js/app/components/PageTracker.tsx b/server/sonar-web/src/main/js/app/components/PageTracker.tsx index a7699df640f..2ae8c85026b 100644 --- a/server/sonar-web/src/main/js/app/components/PageTracker.tsx +++ b/server/sonar-web/src/main/js/app/components/PageTracker.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import * as GoogleAnalytics from 'react-ga'; import { withRouter, WithRouterProps } from 'react-router'; import { connect } from 'react-redux'; -import { getGlobalSettingValue } from '../../store/rootReducer'; +import { getGlobalSettingValue, Store } from '../../store/rootReducer'; interface StateProps { trackingId?: string; @@ -59,8 +59,8 @@ export class PageTracker extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ trackingId: (getGlobalSettingValue(state, 'sonar.analytics.trackingId') || {}).value }); -export default withRouter<{}>(connect<StateProps>(mapStateToProps)(PageTracker)); +export default withRouter(connect(mapStateToProps)(PageTracker)); diff --git a/server/sonar-web/src/main/js/app/components/StartupModal.tsx b/server/sonar-web/src/main/js/app/components/StartupModal.tsx index 9383ec2539e..ee49e969d49 100644 --- a/server/sonar-web/src/main/js/app/components/StartupModal.tsx +++ b/server/sonar-web/src/main/js/app/components/StartupModal.tsx @@ -23,8 +23,8 @@ import { connect } from 'react-redux'; import { CurrentUser, isLoggedIn, Organization } from '../types'; import { differenceInDays, parseDate, toShortNotSoISOString } from '../../helpers/dates'; import { EditionKey } from '../../apps/marketplace/utils'; -import { getCurrentUser, getAppState } from '../../store/rootReducer'; -import { skipOnboarding as skipOnboardingAction } from '../../store/users/actions'; +import { getCurrentUser, getAppState, Store } from '../../store/rootReducer'; +import { skipOnboarding as skipOnboardingAction } from '../../store/users'; import { showLicense } from '../../api/marketplace'; import { hasMessage } from '../../helpers/l10n'; import { save, get } from '../../helpers/storage'; @@ -49,7 +49,7 @@ const TeamOnboardingModal = lazyLoad(() => ); interface StateProps { - canAdmin: boolean; + canAdmin?: boolean; currentEdition?: EditionKey; currentUser: CurrentUser; } @@ -215,7 +215,7 @@ export class StartupModal extends React.PureComponent<Props, State> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ canAdmin: getAppState(state).canAdmin, currentEdition: getAppState(state).edition, currentUser: getCurrentUser(state) @@ -223,7 +223,7 @@ const mapStateToProps = (state: any): StateProps => ({ const mapDispatchToProps: DispatchProps = { skipOnboardingAction }; -export default connect<StateProps, DispatchProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(StartupModal); diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx index e87e82bad4f..3037367c20e 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { fetchPrismicRefs, fetchPrismicNews, PrismicNews } from '../../../api/news'; -import { getGlobalSettingValue } from '../../../store/rootReducer'; +import { getGlobalSettingValue, Store } from '../../../store/rootReducer'; import DateFormatter from '../../../components/intl/DateFormatter'; import ChevronRightIcon from '../../../components/icons-components/ChevronRightcon'; import PlaceholderBar from '../../../components/ui/PlaceholderBar'; @@ -124,8 +124,8 @@ export class ProductNewsMenuItem extends React.PureComponent<Props, State> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ accessToken: (getGlobalSettingValue(state, 'sonar.prismic.accessToken') || {}).value }); -export default connect<StateProps, {}, OwnProps>(mapStateToProps)(ProductNewsMenuItem); +export default connect(mapStateToProps)(ProductNewsMenuItem); diff --git a/server/sonar-web/src/main/js/app/components/extensions/ExtensionContainer.tsx b/server/sonar-web/src/main/js/app/components/extensions/ExtensionContainer.tsx index c3c56057669..a3e36e6c76a 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/ExtensionContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/extensions/ExtensionContainer.tsx @@ -19,16 +19,16 @@ */ import { connect } from 'react-redux'; import Extension from './Extension'; -import { getCurrentUser } from '../../../store/rootReducer'; -import { addGlobalErrorMessage } from '../../../store/globalMessages/duck'; +import { getCurrentUser, Store } from '../../../store/rootReducer'; +import { addGlobalErrorMessage } from '../../../store/globalMessages'; -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ currentUser: getCurrentUser(state) }); const mapDispatchToProps = { onFail: addGlobalErrorMessage }; -export default connect<any, any, any>( +export default connect( mapStateToProps, mapDispatchToProps )(Extension); diff --git a/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx b/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx index c38e996c2a3..a12e39986cd 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx +++ b/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import ExtensionContainer from './ExtensionContainer'; import NotFound from '../NotFound'; -import { getOrganizationByKey } from '../../../store/rootReducer'; +import { getOrganizationByKey, Store } from '../../../store/rootReducer'; import { fetchOrganization } from '../../../apps/organizations/actions'; import { Organization } from '../../types'; @@ -74,13 +74,13 @@ class OrganizationPageExtension extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any, ownProps: OwnProps) => ({ +const mapStateToProps = (state: Store, ownProps: OwnProps) => ({ organization: getOrganizationByKey(state, ownProps.params.organizationKey) }); const mapDispatchToProps = { fetchOrganization }; -export default connect<StateToProps, DispatchProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(OrganizationPageExtension); diff --git a/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.js b/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.js index 45c7a677a18..e39394c6d91 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.js +++ b/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.js @@ -22,7 +22,7 @@ import React from 'react'; import { connect } from 'react-redux'; import ExtensionContainer from './ExtensionContainer'; import NotFound from '../NotFound'; -import { addGlobalErrorMessage } from '../../../store/globalMessages/duck'; +import { addGlobalErrorMessage } from '../../../store/globalMessages'; /*:: type Props = { diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavHeader.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavHeader.tsx index e616861f278..f32e3dfa308 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavHeader.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavHeader.tsx @@ -23,7 +23,11 @@ import { Link } from 'react-router'; import ComponentNavBranch from './ComponentNavBranch'; import { Component, Organization, BranchLike, Breadcrumb } from '../../../types'; import QualifierIcon from '../../../../components/icons-components/QualifierIcon'; -import { getOrganizationByKey, areThereCustomOrganizations } from '../../../../store/rootReducer'; +import { + getOrganizationByKey, + areThereCustomOrganizations, + Store +} from '../../../../store/rootReducer'; import OrganizationAvatar from '../../../../components/common/OrganizationAvatar'; import OrganizationHelmet from '../../../../components/common/OrganizationHelmet'; import OrganizationLink from '../../../../components/ui/OrganizationLink'; @@ -34,7 +38,7 @@ import { isSonarCloud } from '../../../../helpers/system'; interface StateProps { organization?: Organization; - shouldOrganizationBeDisplayed: boolean; + shouldOrganizationBeDisplayed?: boolean; } interface OwnProps { @@ -118,7 +122,7 @@ function renderBreadcrumbs(breadcrumbs: Breadcrumb[]) { }); } -const mapStateToProps = (state: any, ownProps: OwnProps): StateProps => ({ +const mapStateToProps = (state: Store, ownProps: OwnProps): StateProps => ({ organization: getOrganizationByKey(state, ownProps.component.organization), shouldOrganizationBeDisplayed: areThereCustomOrganizations(state) }); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx index 7b2f2e2c221..51babd7921b 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx @@ -40,7 +40,7 @@ import { isPullRequest } from '../../../../helpers/branches'; import { translate } from '../../../../helpers/l10n'; -import { getCurrentUser } from '../../../../store/rootReducer'; +import { getCurrentUser, Store } from '../../../../store/rootReducer'; interface StateProps { currentUser: CurrentUser; @@ -121,7 +121,7 @@ function getCurrentPage(component: Component, branchLike: BranchLike | undefined return currentPage; } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ currentUser: getCurrentUser(state) }); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx index 81619581862..396050e4731 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx @@ -30,7 +30,7 @@ import * as theme from '../../../theme'; import { isLoggedIn, CurrentUser, AppState } from '../../../types'; import NavBar from '../../../../components/nav/NavBar'; import { lazyLoad } from '../../../../components/lazyLoad'; -import { getCurrentUser, getAppState } from '../../../../store/rootReducer'; +import { getCurrentUser, getAppState, Store } from '../../../../store/rootReducer'; import { SuggestionLink } from '../../embed-docs-modal/SuggestionsProvider'; import { isSonarCloud } from '../../../../helpers/system'; import './GlobalNav.css'; @@ -38,7 +38,7 @@ import './GlobalNav.css'; const GlobalNavPlus = lazyLoad(() => import('./GlobalNavPlus')); interface StateProps { - appState: AppState; + appState: Pick<AppState, 'canAdmin' | 'globalPages' | 'organizationsEnabled' | 'qualifiers'>; currentUser: CurrentUser; } @@ -78,9 +78,9 @@ export class GlobalNav extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ currentUser: getCurrentUser(state), appState: getAppState(state) }); -export default connect<StateProps, {}, OwnProps>(mapStateToProps)(GlobalNav); +export default connect(mapStateToProps)(GlobalNav); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.tsx index 7c0121ca23e..876a1ccc62f 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import { Link } from 'react-router'; import { connect } from 'react-redux'; -import { getGlobalSettingValue } from '../../../../store/rootReducer'; +import { getGlobalSettingValue, Store } from '../../../../store/rootReducer'; import { translate } from '../../../../helpers/l10n'; import { getBaseUrl } from '../../../../helpers/urls'; @@ -50,9 +50,9 @@ export function SonarCloudNavBranding() { ); } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ customLogoUrl: (getGlobalSettingValue(state, 'sonar.lf.logoUrl') || {}).value, customLogoWidth: (getGlobalSettingValue(state, 'sonar.lf.logoWidthPx') || {}).value }); -export default connect<StateProps>(mapStateToProps)(GlobalNavBranding); +export default connect(mapStateToProps)(GlobalNavBranding); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx index 6bb9590573a..8856840d3f1 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx @@ -29,7 +29,7 @@ import DropdownIcon from '../../../../components/icons-components/DropdownIcon'; import { isSonarCloud } from '../../../../helpers/system'; interface Props { - appState: AppState; + appState: Pick<AppState, 'canAdmin' | 'globalPages' | 'organizationsEnabled' | 'qualifiers'>; currentUser: CurrentUser; location: { pathname: string }; } diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx index e02817a046d..11f8f734dd7 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx @@ -20,13 +20,13 @@ import { connect } from 'react-redux'; import GlobalNavUser from './GlobalNavUser'; import { Organization } from '../../../types'; -import { getMyOrganizations } from '../../../../store/rootReducer'; +import { getMyOrganizations, Store } from '../../../../store/rootReducer'; interface StateProps { organizations: Organization[]; } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ organizations: getMyOrganizations(state) }); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx index 17ed417200a..3410e31581f 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx @@ -24,7 +24,12 @@ import { isSonarCloud } from '../../../../../helpers/system'; jest.mock('../../../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); -const appState = { qualifiers: [] }; +const appState: GlobalNav['props']['appState'] = { + globalPages: [], + canAdmin: false, + organizationsEnabled: false, + qualifiers: [] +}; const currentUser = { isLoggedIn: false }; const location = { pathname: '' }; diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNav-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNav-test.tsx.snap index 7f6362e4750..1ffdab8f252 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNav-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNav-test.tsx.snap @@ -10,6 +10,9 @@ exports[`should render for SonarCloud 1`] = ` <GlobalNavMenu appState={ Object { + "canAdmin": false, + "globalPages": Array [], + "organizationsEnabled": false, "qualifiers": Array [], } } @@ -47,6 +50,9 @@ exports[`should render for SonarCloud 1`] = ` <Search appState={ Object { + "canAdmin": false, + "globalPages": Array [], + "organizationsEnabled": false, "qualifiers": Array [], } } @@ -59,6 +65,9 @@ exports[`should render for SonarCloud 1`] = ` <Connect(GlobalNavUser) appState={ Object { + "canAdmin": false, + "globalPages": Array [], + "organizationsEnabled": false, "qualifiers": Array [], } } @@ -88,6 +97,9 @@ exports[`should render for SonarQube 1`] = ` <GlobalNavMenu appState={ Object { + "canAdmin": false, + "globalPages": Array [], + "organizationsEnabled": false, "qualifiers": Array [], } } @@ -118,6 +130,9 @@ exports[`should render for SonarQube 1`] = ` <Search appState={ Object { + "canAdmin": false, + "globalPages": Array [], + "organizationsEnabled": false, "qualifiers": Array [], } } @@ -130,6 +145,9 @@ exports[`should render for SonarQube 1`] = ` <Connect(GlobalNavUser) appState={ Object { + "canAdmin": false, + "globalPages": Array [], + "organizationsEnabled": false, "qualifiers": Array [], } } diff --git a/server/sonar-web/src/main/js/app/components/search/Search.d.ts b/server/sonar-web/src/main/js/app/components/search/Search.d.ts index b2590dc00e6..58ceb74bdc0 100644 --- a/server/sonar-web/src/main/js/app/components/search/Search.d.ts +++ b/server/sonar-web/src/main/js/app/components/search/Search.d.ts @@ -21,7 +21,7 @@ import * as React from 'react'; import { CurrentUser, AppState } from '../../types'; export interface Props { - appState: AppState; + appState: Pick<AppState, 'organizationsEnabled'>; currentUser: CurrentUser; } diff --git a/server/sonar-web/src/main/js/store/metrics/actions.js b/server/sonar-web/src/main/js/app/flow-types.js index a271928ce3b..7af83c05ca8 100644 --- a/server/sonar-web/src/main/js/store/metrics/actions.js +++ b/server/sonar-web/src/main/js/app/flow-types.js @@ -31,10 +31,3 @@ qualitative?: boolean, type: string }; */ - -export const RECEIVE_METRICS = 'RECEIVE_METRICS'; - -export const receiveMetrics = (metrics /*: Array<Metric> */) => ({ - type: RECEIVE_METRICS, - metrics -}); diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts index b39b6e62427..3918a750ed3 100644 --- a/server/sonar-web/src/main/js/app/types.ts +++ b/server/sonar-web/src/main/js/app/types.ts @@ -17,6 +17,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { EditionKey } from '../apps/marketplace/utils'; + export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; // Type ordered alphabetically to prevent merge conflicts @@ -34,9 +36,14 @@ export interface AppState { authorizationError?: boolean; branchesEnabled?: boolean; canAdmin?: boolean; + defaultOrganization: string; + edition: EditionKey; globalPages?: Extension[]; organizationsEnabled?: boolean; + productionDatabase: boolean; qualifiers: string[]; + standalone?: boolean; + version: string; } export interface Branch { diff --git a/server/sonar-web/src/main/js/app/utils/addGlobalSuccessMessage.ts b/server/sonar-web/src/main/js/app/utils/addGlobalSuccessMessage.ts index 587316afa26..2e4b82d7dc3 100644 --- a/server/sonar-web/src/main/js/app/utils/addGlobalSuccessMessage.ts +++ b/server/sonar-web/src/main/js/app/utils/addGlobalSuccessMessage.ts @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import getStore from './getStore'; -import * as globalMessages from '../../store/globalMessages/duck'; +import * as globalMessages from '../../store/globalMessages'; export default function addGlobalSuccessMessage(message: string): void { const store = getStore(); diff --git a/server/sonar-web/src/main/js/app/utils/getStore.ts b/server/sonar-web/src/main/js/app/utils/getStore.ts index 477fc5a57b4..dc24f943b46 100644 --- a/server/sonar-web/src/main/js/app/utils/getStore.ts +++ b/server/sonar-web/src/main/js/app/utils/getStore.ts @@ -19,9 +19,9 @@ */ import { Store } from 'redux'; import { AppState, CurrentUser } from '../types'; -import { setAppState } from '../../store/appState/duck'; +import { setAppState } from '../../store/appState'; import rootReducer from '../../store/rootReducer'; -import { receiveCurrentUser } from '../../store/users/actions'; +import { receiveCurrentUser } from '../../store/users'; import configureStore from '../../store/utils/configureStore'; let store: Store<any>; diff --git a/server/sonar-web/src/main/js/app/utils/handleRequiredAuthorization.js b/server/sonar-web/src/main/js/app/utils/handleRequiredAuthorization.js index c264596dcd0..eaa2cf81b75 100644 --- a/server/sonar-web/src/main/js/app/utils/handleRequiredAuthorization.js +++ b/server/sonar-web/src/main/js/app/utils/handleRequiredAuthorization.js @@ -20,7 +20,7 @@ // @flow import getStore from './getStore'; import getHistory from './getHistory'; -import { requireAuthorization } from '../../store/appState/duck'; +import { requireAuthorization } from '../../store/appState'; export default () => { const store = getStore(); diff --git a/server/sonar-web/src/main/js/app/utils/throwGlobalError.ts b/server/sonar-web/src/main/js/app/utils/throwGlobalError.ts index 4d12df06e77..264a3eaac88 100644 --- a/server/sonar-web/src/main/js/app/utils/throwGlobalError.ts +++ b/server/sonar-web/src/main/js/app/utils/throwGlobalError.ts @@ -18,10 +18,18 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import getStore from './getStore'; -import { onFail } from '../../store/rootActions'; +import { parseError } from '../../helpers/request'; +import { addGlobalErrorMessage } from '../../store/globalMessages'; -export default function throwGlobalError({ response }: { response: Response }): Promise<Response> { +export default function throwGlobalError(error: { response: Response }): Promise<Response> { const store = getStore(); - onFail(store.dispatch)({ response }); - return Promise.reject(response); + + // eslint-disable-next-line promise/no-promise-in-callback + parseError(error) + .then(message => { + store.dispatch(addGlobalErrorMessage(message)); + }) + .catch(() => {}); + + return Promise.reject(error.response); } diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/SonarCloudPage.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/SonarCloudPage.tsx index 84b4a99ade7..04e14901929 100644 --- a/server/sonar-web/src/main/js/apps/about/sonarcloud/SonarCloudPage.tsx +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/SonarCloudPage.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { withRouter, WithRouterProps } from 'react-router'; import Footer from './Footer'; -import { getCurrentUser, getMyOrganizations } from '../../../store/rootReducer'; +import { getCurrentUser, getMyOrganizations, Store } from '../../../store/rootReducer'; import { CurrentUser, Organization } from '../../../app/types'; import GlobalContainer from '../../../app/components/GlobalContainer'; @@ -57,11 +57,9 @@ class SonarCloudPage extends React.Component<Props> { } } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ currentUser: getCurrentUser(state), userOrganizations: getMyOrganizations(state) }); -export default withRouter<OwnProps>( - connect<StateProps, {}, OwnProps>(mapStateToProps)(SonarCloudPage) -); +export default withRouter<OwnProps>(connect(mapStateToProps)(SonarCloudPage)); diff --git a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx index c3768ee5e5c..60d47789043 100644 --- a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx +++ b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx @@ -24,14 +24,19 @@ import OrganizationsList from './OrganizationsList'; import CreateOrganizationForm from './CreateOrganizationForm'; import { fetchIfAnyoneCanCreateOrganizations } from './actions'; import { translate } from '../../../helpers/l10n'; -import { getAppState, getMyOrganizations, getGlobalSettingValue } from '../../../store/rootReducer'; +import { + getAppState, + getMyOrganizations, + getGlobalSettingValue, + Store +} from '../../../store/rootReducer'; import { Organization } from '../../../app/types'; import { Button } from '../../../components/ui/buttons'; interface StateProps { anyoneCanCreate?: { value: string }; - canAdmin: boolean; - organizations: Array<Organization>; + canAdmin?: boolean; + organizations: Organization[]; } interface DispatchProps { @@ -110,7 +115,7 @@ class UserOrganizations extends React.PureComponent<Props, State> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ anyoneCanCreate: getGlobalSettingValue(state, 'sonar.organizations.anyoneCanCreate'), canAdmin: getAppState(state).canAdmin, organizations: getMyOrganizations(state) diff --git a/server/sonar-web/src/main/js/apps/account/organizations/actions.ts b/server/sonar-web/src/main/js/apps/account/organizations/actions.ts index 4361e0d0849..7c6e29f7990 100644 --- a/server/sonar-web/src/main/js/apps/account/organizations/actions.ts +++ b/server/sonar-web/src/main/js/apps/account/organizations/actions.ts @@ -19,17 +19,18 @@ */ import { Dispatch } from 'redux'; import { getOrganizations } from '../../../api/organizations'; -import { receiveMyOrganizations } from '../../../store/organizations/duck'; +import { receiveMyOrganizations } from '../../../store/organizations'; import { getValues } from '../../../api/settings'; import { receiveValues } from '../../settings/store/values/actions'; +import { Store } from '../../../store/rootReducer'; -export const fetchMyOrganizations = () => (dispatch: Dispatch<any>) => { +export const fetchMyOrganizations = () => (dispatch: Dispatch<Store>) => { return getOrganizations({ member: true }).then(({ organizations }) => { return dispatch(receiveMyOrganizations(organizations)); }); }; -export const fetchIfAnyoneCanCreateOrganizations = () => (dispatch: Dispatch<any>) => { +export const fetchIfAnyoneCanCreateOrganizations = () => (dispatch: Dispatch<Store>) => { return getValues({ keys: 'sonar.organizations.anyoneCanCreate' }).then(values => { dispatch(receiveValues(values, undefined)); }); diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/StatsContainer.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/StatsContainer.tsx index 09a9d8153ef..f4ab2473ec5 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/StatsContainer.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/StatsContainer.tsx @@ -19,9 +19,9 @@ */ import { connect } from 'react-redux'; import Stats from './Stats'; -import { getAppState } from '../../../store/rootReducer'; +import { getAppState, Store } from '../../../store/rootReducer'; -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ isSystemAdmin: !!getAppState(state).canAdmin }); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx index 8e17a963e70..685d0583940 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx @@ -51,7 +51,7 @@ import FiltersHeader from '../../../components/common/FiltersHeader'; import SearchBox from '../../../components/controls/SearchBox'; import { searchRules, getRulesApp } from '../../../api/rules'; import { searchQualityProfiles, Profile } from '../../../api/quality-profiles'; -import { getCurrentUser, getMyOrganizations } from '../../../store/rootReducer'; +import { getCurrentUser, getMyOrganizations, Store } from '../../../store/rootReducer'; import { translate } from '../../../helpers/l10n'; import { RawQuery } from '../../../helpers/query'; import { scrollToElement } from '../../../helpers/scrolling'; @@ -634,9 +634,9 @@ function parseFacets(rawFacets: { property: string; values: { count: number; val return facets; } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ currentUser: getCurrentUser(state), userOrganizations: getMyOrganizations(state) }); -export default withRouter(connect<StateToProps, {}, OwnProps>(mapStateToProps)(App)); +export default withRouter(connect(mapStateToProps)(App)); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/LanguageFacet.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/LanguageFacet.tsx index 5f0a4132697..252db202d06 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/LanguageFacet.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/LanguageFacet.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { uniqBy } from 'lodash'; import { BasicProps } from './Facet'; -import { getLanguages } from '../../../store/rootReducer'; +import { getLanguages, Store } from '../../../store/rootReducer'; import ListStyleFacet from '../../../components/facet/ListStyleFacet'; import { translate } from '../../../helpers/l10n'; import { highlightTerm } from '../../../helpers/search'; @@ -92,7 +92,7 @@ class LanguageFacet extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ installedLanguages: Object.values(getLanguages(state)) }); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RepositoryFacet.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RepositoryFacet.tsx index a32e7293c26..238aea7a35b 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/RepositoryFacet.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RepositoryFacet.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import Facet, { BasicProps } from './Facet'; -import { getLanguages } from '../../../store/rootReducer'; +import { getLanguages, Store } from '../../../store/rootReducer'; interface StateProps { referencedLanguages: { [language: string]: { key: string; name: string } }; @@ -69,7 +69,7 @@ class RepositoryFacet extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ referencedLanguages: getLanguages(state) }); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/App.js b/server/sonar-web/src/main/js/apps/component-measures/components/App.js index a9e552dc77d..f866fd0dd60 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/App.js +++ b/server/sonar-web/src/main/js/apps/component-measures/components/App.js @@ -36,7 +36,7 @@ import { import { getDisplayMetrics } from '../../../helpers/measures'; /*:: import type { Component, Query, Period } from '../types'; */ /*:: import type { RawQuery } from '../../../helpers/query'; */ -/*:: import type { Metric } from '../../../store/metrics/actions'; */ +/*:: import type { Metric } from '../../../app/flow-types'; */ /*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */ import '../../../components/search-navigator.css'; import '../style.css'; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js index a16978f8c5d..c39214fba0b 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js @@ -31,7 +31,7 @@ import { getMeasureHistoryUrl } from '../../../helpers/urls'; import { isDiffMetric } from '../../../helpers/measures'; /*:: import type { Component, Period } from '../types'; */ /*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */ -/*:: import type { Metric } from '../../../store/metrics/actions'; */ +/*:: import type { Metric } from '../../../app/flow-types'; */ /*:: type Props = {| branchLike?: { id?: string; name: string }, diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js index 83e59016ccb..495626eaede 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js @@ -30,7 +30,7 @@ import { enhanceComponent, getBubbleMetrics, isFileType } from '../utils'; import { getBranchLikeQuery } from '../../../helpers/branches'; import DeferredSpinner from '../../../components/common/DeferredSpinner'; /*:: import type { Component, ComponentEnhanced, Paging, Period } from '../types'; */ -/*:: import type { Metric } from '../../../store/metrics/actions'; */ +/*:: import type { Metric } from '../../../app/flow-types'; */ /*:: type Props = {| branchLike?: { id?: string; name: string }, diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.js index 141cb9839db..db4caed4947 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.js @@ -26,7 +26,7 @@ import { isViewType } from '../utils'; import { getBranchLikeQuery } from '../../../helpers/branches'; /*:: import type { Component, Period, Query } from '../types'; */ /*:: import type { RawQuery } from '../../../helpers/query'; */ -/*:: import type { Metric } from '../../../store/metrics/actions'; */ +/*:: import type { Metric } from '../../../app/flow-types'; */ /*:: type Props = {| branchLike?: { id?: string; name: string }, diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js index 9031eacd7af..7a6fe3264ed 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js @@ -33,7 +33,7 @@ import { import { getBubbleMetrics, getBubbleYDomain, isProjectOverview } from '../utils'; import { RATING_COLORS } from '../../../helpers/constants'; /*:: import type { Component, ComponentEnhanced } from '../types'; */ -/*:: import type { Metric } from '../../../store/metrics/actions'; */ +/*:: import type { Metric } from '../../../app/flow-types'; */ const HEIGHT = 500; diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.js index fc268fa3425..6ec4749855e 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.js +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.js @@ -32,7 +32,7 @@ import { } from '../../../helpers/urls'; import { translate } from '../../../helpers/l10n'; /*:: import type { Component, ComponentEnhanced } from '../types'; */ -/*:: import type { Metric } from '../../../store/metrics/actions'; */ +/*:: import type { Metric } from '../../../app/flow-types'; */ /*:: type Props = { branchLike?: { id?: string; name: string }, diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js index 891bd5b5747..49024fe6f07 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js @@ -23,7 +23,7 @@ import classNames from 'classnames'; import ComponentCell from './ComponentCell'; import MeasureCell from './MeasureCell'; /*:: import type { Component, ComponentEnhanced } from '../types'; */ -/*:: import type { Metric } from '../../../store/metrics/actions'; */ +/*:: import type { Metric } from '../../../app/flow-types'; */ /*:: type Props = {| branchLike?: { id?: string; name: string }, diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js index da55b93966d..8a984c5001f 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js @@ -23,7 +23,7 @@ import Measure from '../../../components/measure/Measure'; import { isDiffMetric } from '../../../helpers/measures'; /*:: import type { ComponentEnhanced } from '../types'; */ /*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */ -/*:: import type { Metric } from '../../../store/metrics/actions'; */ +/*:: import type { Metric } from '../../../app/flow-types'; */ /*:: type Props = { component: ComponentEnhanced, diff --git a/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx b/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx index b5c65fd6ed5..ed8f05fec88 100644 --- a/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx +++ b/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx @@ -22,7 +22,7 @@ import { connect } from 'react-redux'; import AppContainer from './components/AppContainer'; import { CurrentUser, isLoggedIn } from '../../app/types'; import { RawQuery } from '../../helpers/query'; -import { getCurrentUser } from '../../store/rootReducer'; +import { getCurrentUser, Store } from '../../store/rootReducer'; import { isSonarCloud } from '../../helpers/system'; interface StateProps { @@ -38,8 +38,8 @@ function IssuesPage({ currentUser, location }: Props) { return <AppContainer location={location} myIssues={myIssues} />; } -const stateToProps = (state: any) => ({ +const stateToProps = (state: Store) => ({ currentUser: getCurrentUser(state) }); -export default connect<StateProps>(stateToProps)(IssuesPage); +export default connect(stateToProps)(IssuesPage); diff --git a/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx b/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx index a2c5a09d56a..929acb305c0 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx @@ -27,24 +27,25 @@ import throwGlobalError from '../../../app/utils/throwGlobalError'; import { getCurrentUser, areThereCustomOrganizations, - getMyOrganizations + getMyOrganizations, + Store } from '../../../store/rootReducer'; import { lazyLoad } from '../../../components/lazyLoad'; import { parseIssueFromResponse } from '../../../helpers/issues'; import { RawQuery } from '../../../helpers/query'; -import { receiveOrganizations } from '../../../store/organizations/duck'; +import { receiveOrganizations } from '../../../store/organizations'; interface StateProps { currentUser: CurrentUser; userOrganizations: Organization[]; } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ currentUser: getCurrentUser(state), userOrganizations: getMyOrganizations(state) }); -const fetchIssueOrganizations = (organizationKeys: string[]) => (dispatch: Dispatch<any>) => { +const fetchIssueOrganizations = (organizationKeys: string[]) => (dispatch: Dispatch<Store>) => { if (!organizationKeys.length) { return Promise.resolve(); } @@ -58,7 +59,7 @@ const fetchIssueOrganizations = (organizationKeys: string[]) => (dispatch: Dispa const fetchIssues = (query: RawQuery, requestOrganizations = true) => ( // use `Function` to be able to do `dispatch(...).then(...)` dispatch: Function, - getState: () => any + getState: () => Store ) => { const organizationsEnabled = areThereCustomOrganizations(getState()); return searchIssues({ ...query, additionalFields: '_all' }) @@ -87,13 +88,7 @@ interface DispatchProps { // have to type cast this, because of async action const mapDispatchToProps = { fetchIssues: fetchIssues as any } as DispatchProps; -interface OwnProps { - location: { pathname: string; query: RawQuery }; - hideAuthorFacet?: boolean; - myIssues?: boolean; -} - -export default connect<StateProps, DispatchProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(lazyLoad(() => import('./App'))); diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx index b5d2fb47474..2dca1a25952 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx @@ -22,7 +22,7 @@ import { uniqBy, omit } from 'lodash'; import { connect } from 'react-redux'; import ListStyleFacet from '../../../components/facet/ListStyleFacet'; import { Query, ReferencedLanguage, Facet } from '../utils'; -import { getLanguages } from '../../../store/rootReducer'; +import { getLanguages, Store } from '../../../store/rootReducer'; import { translate } from '../../../helpers/l10n'; import { highlightTerm } from '../../../helpers/search'; @@ -107,7 +107,7 @@ class LanguageFacet extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ installedLanguages: Object.values(getLanguages(state)) }); diff --git a/server/sonar-web/src/main/js/apps/marketplace/App.tsx b/server/sonar-web/src/main/js/apps/marketplace/App.tsx index 394c96e750e..2233c8542e1 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/App.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/App.tsx @@ -45,7 +45,7 @@ export interface Props { fetchPendingPlugins: () => void; location: { pathname: string; query: RawQuery }; pendingPlugins: PluginPendingResult; - standaloneMode: boolean; + standaloneMode?: boolean; updateCenterActive: boolean; } diff --git a/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx b/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx index c68c26b11c9..76627ae77bd 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import App from './App'; import { EditionKey } from './utils'; -import { getAppState, getGlobalSettingValue } from '../../store/rootReducer'; +import { getAppState, getGlobalSettingValue, Store } from '../../store/rootReducer'; import { RawQuery } from '../../helpers/query'; import MarketplaceContext from '../../app/components/MarketplaceContext'; @@ -31,11 +31,11 @@ interface OwnProps { interface StateToProps { currentEdition?: EditionKey; - standaloneMode: boolean; + standaloneMode?: boolean; updateCenterActive: boolean; } -const mapStateToProps = (state: any) => { +const mapStateToProps = (state: Store) => { return { currentEdition: getAppState(state).edition, standaloneMode: getAppState(state).standalone, @@ -52,4 +52,4 @@ const WithMarketplaceContext = (props: StateToProps & OwnProps) => ( </MarketplaceContext.Consumer> ); -export default connect<StateToProps, {}, OwnProps>(mapStateToProps)(WithMarketplaceContext); +export default connect(mapStateToProps)(WithMarketplaceContext); diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembersContainer.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembersContainer.tsx index 6f13da8a3c2..c2b0821b83e 100644 --- a/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembersContainer.tsx +++ b/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembersContainer.tsx @@ -20,7 +20,7 @@ import { connect } from 'react-redux'; import OrganizationMembers from './OrganizationMembers'; import { Organization } from '../../app/types'; -import { getOrganizationByKey } from '../../store/rootReducer'; +import { getOrganizationByKey, Store } from '../../store/rootReducer'; interface OwnProps { params: { organizationKey: string }; @@ -30,11 +30,8 @@ interface StateProps { organization: Organization; } -const mapStateToProps = (state: any, ownProps: OwnProps): StateProps => { - const { organizationKey } = ownProps.params; - return { - organization: getOrganizationByKey(state, organizationKey)! - }; +const mapStateToProps = (state: Store, ownProps: OwnProps): StateProps => { + return { organization: getOrganizationByKey(state, ownProps.params.organizationKey) }; }; -export default connect<StateProps, {}, OwnProps>(mapStateToProps)(OrganizationMembers); +export default connect(mapStateToProps)(OrganizationMembers); diff --git a/server/sonar-web/src/main/js/apps/organizations/actions.ts b/server/sonar-web/src/main/js/apps/organizations/actions.ts index ee00b6b3147..682774ff3fa 100644 --- a/server/sonar-web/src/main/js/apps/organizations/actions.ts +++ b/server/sonar-web/src/main/js/apps/organizations/actions.ts @@ -19,51 +19,47 @@ */ import { Dispatch } from 'redux'; import * as api from '../../api/organizations'; -import * as actions from '../../store/organizations/duck'; -import { onFail } from '../../store/rootActions'; -import { addGlobalSuccessMessage } from '../../store/globalMessages/duck'; +import * as actions from '../../store/organizations'; +import { addGlobalSuccessMessage } from '../../store/globalMessages'; import { translate, translateWithParameters } from '../../helpers/l10n'; import { Organization, OrganizationBase } from '../../app/types'; +import { Store } from '../../store/rootReducer'; -const onRejected = (dispatch: Dispatch<any>) => (error: any) => { - onFail(dispatch)(error); - return Promise.reject(error); -}; - -export const fetchOrganization = (key: string) => (dispatch: Dispatch<any>) => { +export const fetchOrganization = (key: string) => (dispatch: Dispatch<Store>) => { return Promise.all([api.getOrganization(key), api.getOrganizationNavigation(key)]).then( ([organization, navigation]) => { if (organization) { const organizationWithPermissions = { ...organization, ...navigation }; dispatch(actions.receiveOrganizations([organizationWithPermissions])); } - }, - onFail(dispatch) + } ); }; -export const createOrganization = (organization: OrganizationBase) => (dispatch: Dispatch<any>) => { +export const createOrganization = (organization: OrganizationBase) => ( + dispatch: Dispatch<Store> +) => { return api.createOrganization(organization).then((organization: Organization) => { dispatch(actions.createOrganization(organization)); dispatch( addGlobalSuccessMessage(translateWithParameters('organization.created', organization.name)) ); return organization; - }, onRejected(dispatch)); + }); }; export const updateOrganization = (key: string, changes: OrganizationBase) => ( - dispatch: Dispatch<any> + dispatch: Dispatch<Store> ) => { return api.updateOrganization(key, changes).then(() => { dispatch(actions.updateOrganization(key, changes)); dispatch(addGlobalSuccessMessage(translate('organization.updated'))); - }, onFail(dispatch)); + }); }; -export const deleteOrganization = (key: string) => (dispatch: Dispatch<any>) => { +export const deleteOrganization = (key: string) => (dispatch: Dispatch<Store>) => { return api.deleteOrganization(key).then(() => { dispatch(actions.deleteOrganization(key)); dispatch(addGlobalSuccessMessage(translate('organization.deleted'))); - }, onFail(dispatch)); + }); }; diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx index 53941adef8a..e1b30839a39 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { RouterState } from 'react-router'; -import { getCurrentUser, getOrganizationByKey } from '../../../store/rootReducer'; +import { getCurrentUser, getOrganizationByKey, Store } from '../../../store/rootReducer'; import handleRequiredAuthorization from '../../../app/utils/handleRequiredAuthorization'; import { Organization, CurrentUser, isLoggedIn } from '../../../app/types'; @@ -63,14 +63,12 @@ export class OrganizationAccess extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any, ownProps: OwnProps) => ({ +const mapStateToProps = (state: Store, ownProps: OwnProps) => ({ currentUser: getCurrentUser(state), organization: getOrganizationByKey(state, ownProps.params.organizationKey) }); -const OrganizationAccessContainer = connect<StateToProps, {}, OwnProps>(mapStateToProps)( - OrganizationAccess -); +const OrganizationAccessContainer = connect(mapStateToProps)(OrganizationAccess); export function hasAdminAccess({ currentUser, diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationContainer.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationContainer.tsx index 08d359b25a8..baadb3fd4cd 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationContainer.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationContainer.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { RouterState } from 'react-router'; -import { getCurrentUser, getOrganizationByKey } from '../../../store/rootReducer'; +import { getCurrentUser, getOrganizationByKey, Store } from '../../../store/rootReducer'; import { Organization, CurrentUser } from '../../../app/types'; interface StateToProps { @@ -44,9 +44,9 @@ class OrganizationContainer extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any, ownProps: OwnProps) => ({ +const mapStateToProps = (state: Store, ownProps: OwnProps) => ({ organization: getOrganizationByKey(state, ownProps.params.organizationKey), currentUser: getCurrentUser(state) }); -export default connect<StateToProps, {}, OwnProps>(mapStateToProps)(OrganizationContainer); +export default connect(mapStateToProps)(OrganizationContainer); diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx index c1aac8ef5d6..b3b7eb5711b 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx @@ -128,7 +128,7 @@ export class OrganizationDelete extends React.PureComponent<Props, State> { const mapDispatchToProps: DispatchToProps = { deleteOrganization: deleteOrganization as any }; -export default connect<null, DispatchToProps, OwnProps>( +export default connect( null, mapDispatchToProps )(OrganizationDelete); diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx index a81cbe614d3..fa0bb5ca7f2 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx @@ -197,7 +197,7 @@ export class OrganizationEdit extends React.PureComponent<Props, State> { const mapDispatchToProps = { updateOrganization: updateOrganization as any }; -export default connect<{}, DispatchProps, OwnProps>( +export default connect( null, mapDispatchToProps )(OrganizationEdit); diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationPage.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationPage.tsx index 41981090047..a4581693d1b 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationPage.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationPage.tsx @@ -28,7 +28,8 @@ import { Organization, CurrentUser } from '../../../app/types'; import { getOrganizationByKey, getCurrentUser, - getMyOrganizations + getMyOrganizations, + Store } from '../../../store/rootReducer'; interface OwnProps { @@ -110,7 +111,7 @@ export class OrganizationPage extends React.PureComponent<Props, State> { } } -const mapStateToProps = (state: any, ownProps: OwnProps) => ({ +const mapStateToProps = (state: Store, ownProps: OwnProps) => ({ currentUser: getCurrentUser(state), organization: getOrganizationByKey(state, ownProps.params.organizationKey), userOrganizations: getMyOrganizations(state) @@ -118,7 +119,7 @@ const mapStateToProps = (state: any, ownProps: OwnProps) => ({ const mapDispatchToProps = { fetchOrganization: fetchOrganization as any }; -export default connect<StateProps, DispatchToProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(OrganizationPage); diff --git a/server/sonar-web/src/main/js/apps/organizations/forSingleOrganization.tsx b/server/sonar-web/src/main/js/apps/organizations/forSingleOrganization.tsx index 4ec2c2a2132..4dabbca6786 100644 --- a/server/sonar-web/src/main/js/apps/organizations/forSingleOrganization.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/forSingleOrganization.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { withRouter, WithRouterProps } from 'react-router'; -import { areThereCustomOrganizations } from '../../store/rootReducer'; +import { areThereCustomOrganizations, Store } from '../../store/rootReducer'; type ReactComponent<P> = React.ComponentClass<P> | React.StatelessComponent<P>; @@ -44,7 +44,7 @@ export default function forSingleOrganization<P>(ComposedComponent: ReactCompone } } - const mapStateToProps = (state: any) => ({ + const mapStateToProps = (state: Store) => ({ customOrganizations: areThereCustomOrganizations(state) }); diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeaderContainer.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeaderContainer.tsx index 88b71f90e41..fb6b23e087b 100644 --- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeaderContainer.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeaderContainer.tsx @@ -20,13 +20,13 @@ import { connect } from 'react-redux'; import OrganizationNavigationHeader from './OrganizationNavigationHeader'; import { Organization } from '../../../app/types'; -import { getMyOrganizations } from '../../../store/rootReducer'; +import { getMyOrganizations, Store } from '../../../store/rootReducer'; interface StateProps { organizations: Organization[]; } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ organizations: getMyOrganizations(state) }); diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx index 07ee53cd586..518a2a86c52 100644 --- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx @@ -27,7 +27,7 @@ import NavBarTabs from '../../../components/nav/NavBarTabs'; import { translate } from '../../../helpers/l10n'; import { getQualityGatesUrl } from '../../../helpers/urls'; import { hasPrivateAccess, isCurrentUserMemberOf } from '../../../helpers/organizations'; -import { getCurrentUser, getMyOrganizations } from '../../../store/rootReducer'; +import { getCurrentUser, getMyOrganizations, Store } from '../../../store/rootReducer'; interface StateToProps { currentUser: CurrentUser; @@ -99,9 +99,9 @@ export function OrganizationNavigationMenu({ ); } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ currentUser: getCurrentUser(state), userOrganizations: getMyOrganizations(state) }); -export default connect<StateToProps, {}, OwnProps>(mapStateToProps)(OrganizationNavigationMenu); +export default connect(mapStateToProps)(OrganizationNavigationMenu); diff --git a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx index dc61e0ef7a8..3f6982b4696 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx @@ -47,7 +47,7 @@ import { isLongLivingBranch } from '../../../helpers/branches'; import { fetchMetrics } from '../../../store/rootActions'; -import { getMetrics } from '../../../store/rootReducer'; +import { getMetrics, Store } from '../../../store/rootReducer'; import { BranchLike, Component, Metric, MeasureEnhanced } from '../../../app/types'; import { translate } from '../../../helpers/l10n'; import '../styles.css'; @@ -262,11 +262,11 @@ export class OverviewApp extends React.PureComponent<Props, State> { const mapDispatchToProps: DispatchToProps = { fetchMetrics }; -const mapStateToProps = (state: any): StateToProps => ({ +const mapStateToProps = (state: Store): StateToProps => ({ metrics: getMetrics(state) }); -export default connect<StateToProps, DispatchToProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(OverviewApp); diff --git a/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx index 53dace6236e..5cf37a984c5 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx @@ -25,7 +25,7 @@ import MetaContainer from '../meta/MetaContainer'; import { BranchLike, Component, CurrentUser, isLoggedIn } from '../../../app/types'; import { isLongLivingBranch, isBranch, isMainBranch } from '../../../helpers/branches'; import { translate } from '../../../helpers/l10n'; -import { getCurrentUser } from '../../../store/rootReducer'; +import { getCurrentUser, Store } from '../../../store/rootReducer'; import '../../../app/styles/sonarcloud.css'; interface OwnProps { @@ -119,8 +119,8 @@ export function WarningMessage({ ); } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ currentUser: getCurrentUser(state) }); -export default connect<StateProps, {}, OwnProps>(mapStateToProps)(SonarCloudEmptyOverview); +export default connect(mapStateToProps)(SonarCloudEmptyOverview); diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx index cd93c3a9fbd..e6aba6d12c2 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx @@ -44,7 +44,8 @@ import { hasPrivateAccess } from '../../../helpers/organizations'; import { getCurrentUser, getMyOrganizations, - getOrganizationByKey + getOrganizationByKey, + Store } from '../../../store/rootReducer'; import PrivacyBadgeContainer from '../../../components/common/PrivacyBadgeContainer'; @@ -170,10 +171,10 @@ export class Meta extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any, { component }: OwnProps) => ({ +const mapStateToProps = (state: Store, { component }: OwnProps) => ({ currentUser: getCurrentUser(state), organization: getOrganizationByKey(state, component.organization), userOrganizations: getMyOrganizations(state) }); -export default connect<StateToProps, {}, OwnProps>(mapStateToProps)(Meta); +export default connect(mapStateToProps)(Meta); diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.tsx index a4628b8fa6e..eb8f8fc45f0 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.tsx @@ -25,7 +25,7 @@ import Tooltip from '../../../components/controls/Tooltip'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { getQualityProfileUrl } from '../../../helpers/urls'; import { searchRules } from '../../../api/rules'; -import { getLanguages } from '../../../store/rootReducer'; +import { getLanguages, Store } from '../../../store/rootReducer'; import { ComponentQualityProfile } from '../../../app/types'; interface StateProps { @@ -147,8 +147,8 @@ class MetaQualityProfiles extends React.PureComponent<StateProps & OwnProps, Sta } } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ languages: getLanguages(state) }); -export default connect<StateProps, {}, OwnProps>(mapStateToProps)(MetaQualityProfiles); +export default connect(mapStateToProps)(MetaQualityProfiles); diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx index 4fdc6e23ebf..8ef1bc6c4a8 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx @@ -67,7 +67,7 @@ export default class MetaSize extends React.PureComponent<Props> { const className = this.props.component.qualifier === 'TRK' ? 'overview-meta-size-lang-dist' : 'big-spacer-top'; - return languageDistribution ? ( + return languageDistribution && languageDistribution.value !== undefined ? ( <div className={className} id="overview-language-distribution"> <LanguageDistributionContainer distribution={languageDistribution.value} width={160} /> </div> diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersListContainer.tsx b/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersListContainer.tsx index 40067a021cb..66203598154 100644 --- a/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersListContainer.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersListContainer.tsx @@ -17,6 +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 } from 'react-redux'; import AllHoldersList from './AllHoldersList'; import { @@ -34,35 +35,16 @@ import { getPermissionsAppGroups, getPermissionsAppQuery, getPermissionsAppFilter, - getPermissionsAppSelectedPermission + getPermissionsAppSelectedPermission, + Store } from '../../../../store/rootReducer'; import { Organization } from '../../../../app/types'; -import { PermissionUser, PermissionGroup } from '../../../../api/permissions'; interface OwnProps { organization?: Organization; } -interface StateToProps { - filter: string; - groups: PermissionGroup[]; - query: string; - selectedPermission?: string; - users: PermissionUser[]; -} - -interface DispatchToProps { - grantPermissionToGroup: (groupName: string, permission: string) => Promise<void>; - grantPermissionToUser: (login: string, permission: string) => Promise<void>; - loadHolders: () => void; - onFilter: (filter: string) => void; - onSearch: (query: string) => void; - onSelectPermission: (permission: string) => void; - revokePermissionFromGroup: (groupName: string, permission: string) => Promise<void>; - revokePermissionFromUser: (login: string, permission: string) => Promise<void>; -} - -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ filter: getPermissionsAppFilter(state), groups: getPermissionsAppGroups(state), query: getPermissionsAppQuery(state), @@ -70,7 +52,7 @@ const mapStateToProps = (state: any) => ({ users: getPermissionsAppUsers(state) }); -const mapDispatchToProps = (dispatch: Function, ownProps: OwnProps) => { +const mapDispatchToProps = (dispatch: Dispatch<Store>, ownProps: OwnProps) => { const organizationKey = ownProps.organization ? ownProps.organization.key : undefined; return { grantPermissionToGroup: (groupName: string, permission: string) => @@ -89,7 +71,7 @@ const mapDispatchToProps = (dispatch: Function, ownProps: OwnProps) => { }; }; -export default connect<StateToProps, DispatchToProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(AllHoldersList); diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/App.js b/server/sonar-web/src/main/js/apps/permissions/project/components/App.js index c39d78e3d30..28f20e3ef74 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/App.js +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/App.js @@ -45,8 +45,7 @@ export type Props = {| qualifier: string, visibility: string }, - onComponentChange: (changes: {}) => void, - onRequestFail: Object => void + onComponentChange: (changes: {}) => void |}; */ @@ -208,7 +207,6 @@ export default class App extends React.PureComponent { loading: false, groups: this.removePermissionFromGroup(group, permission) }); - this.props.onRequestFail(error); } }); } @@ -231,7 +229,6 @@ export default class App extends React.PureComponent { loading: false, users: this.removePermissionFromUser(user, permission) }); - this.props.onRequestFail(error); } }); } @@ -254,7 +251,6 @@ export default class App extends React.PureComponent { loading: false, groups: this.addPermissionToGroup(group, permission) }); - this.props.onRequestFail(error); } }); } @@ -277,7 +273,6 @@ export default class App extends React.PureComponent { loading: false, users: this.addPermissionToUser(user, permission) }); - this.props.onRequestFail(error); } }); } diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.js b/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.js index b95e406649f..2dcc1210a03 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.js +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.js @@ -19,18 +19,10 @@ */ import { connect } from 'react-redux'; import App from './App'; -import { onFail } from '../../../../store/rootActions'; import { getCurrentUser } from '../../../../store/rootReducer'; const mapStateToProps = state => ({ currentUser: getCurrentUser(state) }); -const mapDispatchToProps = dispatch => ({ - onRequestFail: onFail(dispatch) -}); - -export default connect( - mapStateToProps, - mapDispatchToProps -)(App); +export default connect(mapStateToProps)(App); diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.tsx b/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.tsx index c28badc0fb3..cd2f3c0e89e 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import { connect } from 'react-redux'; -import { getPermissionsAppError } from '../../../../store/rootReducer'; +import { getPermissionsAppError, Store } from '../../../../store/rootReducer'; interface Props { message: string; @@ -33,7 +33,7 @@ function PageError({ message }: Props) { return <div className="alert alert-danger">{message}</div>; } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ message: getPermissionsAppError(state) }); diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx index e12f6f7edc1..b5bef871e77 100644 --- a/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx @@ -33,7 +33,7 @@ import { getMeasures } from '../../../api/measures'; import { getChildren } from '../../../api/components'; import { translate } from '../../../helpers/l10n'; import { fetchMetrics } from '../../../store/rootActions'; -import { getMetrics } from '../../../store/rootReducer'; +import { getMetrics, Store } from '../../../store/rootReducer'; import { Metric, Component } from '../../../app/types'; import '../styles.css'; import PrivacyBadgeContainer from '../../../components/common/PrivacyBadgeContainer'; @@ -220,11 +220,11 @@ export class App extends React.PureComponent<Props, State> { const mapDispatchToProps: DispatchToProps = { fetchMetrics }; -const mapStateToProps = (state: any): StateToProps => ({ +const mapStateToProps = (state: Store): StateToProps => ({ metrics: getMetrics(state) }); -export default connect<StateToProps, DispatchToProps, Props>( +export default connect( mapStateToProps, mapDispatchToProps )(App); diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/Subscription.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/Subscription.tsx index e15edf3ad7c..79558f42221 100644 --- a/server/sonar-web/src/main/js/apps/portfolio/components/Subscription.tsx +++ b/server/sonar-web/src/main/js/apps/portfolio/components/Subscription.tsx @@ -22,10 +22,11 @@ import AlertSuccessIcon from '../../../components/icons-components/AlertSuccessI import { ReportStatus, subscribe, unsubscribe } from '../../../api/report'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { Button } from '../../../components/ui/buttons'; +import { CurrentUser, isLoggedIn } from '../../../app/types'; interface Props { component: string; - currentUser: { email?: string }; + currentUser: CurrentUser; status: ReportStatus; } @@ -116,7 +117,7 @@ export default class Subscription extends React.PureComponent<Props, State> { ); render() { - const hasEmail = !!this.props.currentUser.email; + const hasEmail = isLoggedIn(this.props.currentUser) && !!this.props.currentUser.email; const { subscribed } = this.state; let inner; diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/SubscriptionContainer.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/SubscriptionContainer.tsx index d863f9494b6..4076247a18f 100644 --- a/server/sonar-web/src/main/js/apps/portfolio/components/SubscriptionContainer.tsx +++ b/server/sonar-web/src/main/js/apps/portfolio/components/SubscriptionContainer.tsx @@ -19,10 +19,10 @@ */ import { connect } from 'react-redux'; import Subscription from './Subscription'; -import { getCurrentUser } from '../../../store/rootReducer'; +import { getCurrentUser, Store } from '../../../store/rootReducer'; -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ currentUser: getCurrentUser(state) }); -export default connect<any, any, any>(mapStateToProps)(Subscription); +export default connect(mapStateToProps)(Subscription); diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/Subscription-test.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/Subscription-test.tsx index da053905930..c5e364751bb 100644 --- a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/Subscription-test.tsx +++ b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/Subscription-test.tsx @@ -41,7 +41,7 @@ const status = { subscribed: true }; -const currentUser = { email: 'foo@example.com' }; +const currentUser = { isLoggedIn: true, email: 'foo@example.com' }; beforeEach(() => { subscribe.mockClear(); @@ -68,7 +68,7 @@ it('renders when not subscribed', () => { it('renders when no email', () => { expect( - shallow(<Subscription component="foo" currentUser={{}} status={status} />) + shallow(<Subscription component="foo" currentUser={{ isLoggedIn: false }} status={status} />) ).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdate.js b/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdate.js index 9919f4b8604..827c7872c36 100644 --- a/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdate.js +++ b/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdate.js @@ -30,7 +30,7 @@ import { addGlobalErrorMessage, addGlobalSuccessMessage, closeAllGlobalMessages -} from '../../../store/globalMessages/duck'; +} from '../../../store/globalMessages'; import RecentHistory from '../../../app/components/RecentHistory'; class BulkUpdate extends React.PureComponent { diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/Key.js b/server/sonar-web/src/main/js/apps/project-admin/key/Key.js index 2d272a903ad..b16f0f396d8 100644 --- a/server/sonar-web/src/main/js/apps/project-admin/key/Key.js +++ b/server/sonar-web/src/main/js/apps/project-admin/key/Key.js @@ -32,7 +32,7 @@ import { addGlobalErrorMessage, addGlobalSuccessMessage, closeAllGlobalMessages -} from '../../../store/globalMessages/duck'; +} from '../../../store/globalMessages'; import RecentHistory from '../../../app/components/RecentHistory'; import { getProjectAdminProjectModules } from '../../../store/rootReducer'; diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/AppContainer.ts b/server/sonar-web/src/main/js/apps/projectBranches/components/AppContainer.ts index b6ee8558bae..6be51b99452 100644 --- a/server/sonar-web/src/main/js/apps/projectBranches/components/AppContainer.ts +++ b/server/sonar-web/src/main/js/apps/projectBranches/components/AppContainer.ts @@ -19,10 +19,10 @@ */ import { connect } from 'react-redux'; import App from './App'; -import { getAppState } from '../../../store/rootReducer'; +import { getAppState, Store } from '../../../store/rootReducer'; -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ canAdmin: getAppState(state).canAdmin }); -export default connect<any, any, any>(mapStateToProps)(App); +export default connect(mapStateToProps)(App); diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx index 2bf13b590b5..cb7a50672a7 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx @@ -46,7 +46,7 @@ export interface Props { isFavorite: boolean; location: { pathname: string; query: RawQuery }; organization: Organization | undefined; - organizationsEnabled: boolean; + organizationsEnabled?: boolean; storageOptionsSuffix?: string; } diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx index cf7600a82b6..178c281bd33 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx @@ -18,28 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; -import { CurrentUser, Organization } from '../../../app/types'; import { lazyLoad } from '../../../components/lazyLoad'; -import { getCurrentUser, areThereCustomOrganizations } from '../../../store/rootReducer'; -import { RawQuery } from '../../../helpers/query'; +import { getCurrentUser, areThereCustomOrganizations, Store } from '../../../store/rootReducer'; -interface StateProps { - currentUser: CurrentUser; - organizationsEnabled: boolean; -} - -interface OwnProps { - isFavorite: boolean; - location: { pathname: string; query: RawQuery }; - organization: Organization | undefined; - storageOptionsSuffix?: string; -} - -const stateToProps = (state: any) => ({ +const stateToProps = (state: Store) => ({ currentUser: getCurrentUser(state), organizationsEnabled: areThereCustomOrganizations(state) }); -export default connect<StateProps, {}, OwnProps>(stateToProps)( - lazyLoad(() => import('./AllProjects')) -); +export default connect(stateToProps)(lazyLoad(() => import('./AllProjects'))); diff --git a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelectorContainer.tsx b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelectorContainer.tsx index f9cacdeec53..f6a4309f37a 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelectorContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelectorContainer.tsx @@ -19,15 +19,10 @@ */ import { connect } from 'react-redux'; import DefaultPageSelector from './DefaultPageSelector'; -import { CurrentUser } from '../../../app/types'; -import { getCurrentUser } from '../../../store/rootReducer'; +import { getCurrentUser, Store } from '../../../store/rootReducer'; -interface StateProps { - currentUser: CurrentUser; -} - -const stateToProps = (state: any) => ({ +const stateToProps = (state: Store) => ({ currentUser: getCurrentUser(state) }); -export default connect<StateProps>(stateToProps)(DefaultPageSelector); +export default connect(stateToProps)(DefaultPageSelector); diff --git a/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilterContainer.tsx b/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilterContainer.tsx index a869603b9ba..b8f0a49b4a0 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilterContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilterContainer.tsx @@ -19,9 +19,9 @@ */ import { connect } from 'react-redux'; import FavoriteFilter from './FavoriteFilter'; -import { getCurrentUser } from '../../../store/rootReducer'; +import { getCurrentUser, Store } from '../../../store/rootReducer'; -function mapStateToProps(state: any) { +function mapStateToProps(state: Store) { return { currentUser: getCurrentUser(state) }; } diff --git a/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx b/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx index 271cf360e29..e7d683038c3 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx @@ -26,7 +26,7 @@ import DropdownIcon from '../../../components/icons-components/DropdownIcon'; import Dropdown from '../../../components/controls/Dropdown'; import OrganizationListItem from '../../../components/ui/OrganizationListItem'; import { Button } from '../../../components/ui/buttons'; -import { getMyOrganizations } from '../../../store/rootReducer'; +import { getMyOrganizations, Store } from '../../../store/rootReducer'; import { isSonarCloud } from '../../../helpers/system'; import { Organization } from '../../../app/types'; import { translate } from '../../../helpers/l10n'; @@ -95,7 +95,7 @@ export class NoFavoriteProjects extends React.PureComponent<StateProps> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ organizations: getMyOrganizations(state) }); diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLanguages.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLanguages.tsx index 8d0815a9eb4..1fd92c29037 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLanguages.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLanguages.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import { sortBy } from 'lodash'; import Tooltip from '../../../components/controls/Tooltip'; import { translate } from '../../../helpers/l10n'; -import { Languages } from '../../../store/languages/reducer'; +import { Languages } from '../../../store/languages'; interface Props { distribution?: string; diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLanguagesContainer.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLanguagesContainer.tsx index 9e67998c03a..31e30c841d3 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLanguagesContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLanguagesContainer.tsx @@ -19,15 +19,10 @@ */ import { connect } from 'react-redux'; import ProjectCardLanguages from './ProjectCardLanguages'; -import { Languages } from '../../../store/languages/reducer'; -import { getLanguages } from '../../../store/rootReducer'; +import { getLanguages, Store } from '../../../store/rootReducer'; -interface StateProps { - languages: Languages; -} - -const stateToProps = (state: any) => ({ +const stateToProps = (state: Store) => ({ languages: getLanguages(state) }); -export default connect<StateProps>(stateToProps)(ProjectCardLanguages); +export default connect(stateToProps)(ProjectCardLanguages); diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOrganization.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOrganization.tsx index 3341a0a57fa..32b1a71864d 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOrganization.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOrganization.tsx @@ -22,7 +22,7 @@ import OrganizationLink from '../../../components/ui/OrganizationLink'; interface Props { organization?: { key: string; name: string }; - organizationsEnabled: boolean; + organizationsEnabled?: boolean; } export default function ProjectCardOrganization({ organization, organizationsEnabled }: Props) { diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOrganizationContainer.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOrganizationContainer.tsx index da7c8856be7..e637927e23d 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOrganizationContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOrganizationContainer.tsx @@ -19,14 +19,10 @@ */ import { connect } from 'react-redux'; import ProjectCardOrganization from './ProjectCardOrganization'; -import { areThereCustomOrganizations } from '../../../store/rootReducer'; +import { areThereCustomOrganizations, Store } from '../../../store/rootReducer'; -interface StateProps { - organizationsEnabled: boolean; -} - -const stateToProps = (state: any) => ({ +const stateToProps = (state: Store) => ({ organizationsEnabled: areThereCustomOrganizations(state) }); -export default connect<StateProps>(stateToProps)(ProjectCardOrganization); +export default connect(stateToProps)(ProjectCardOrganization); diff --git a/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx b/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx index 41a518401c7..7e27c4accff 100644 --- a/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx +++ b/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx @@ -28,9 +28,9 @@ import ManualProjectCreate from './ManualProjectCreate'; import { serializeQuery, Query, parseQuery } from './utils'; import DeferredSpinner from '../../../components/common/DeferredSpinner'; import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication'; -import { getCurrentUser } from '../../../store/rootReducer'; -import { addGlobalErrorMessage } from '../../../store/globalMessages/duck'; -import { skipOnboarding as skipOnboardingAction } from '../../../store/users/actions'; +import { getCurrentUser, Store } from '../../../store/rootReducer'; +import { addGlobalErrorMessage } from '../../../store/globalMessages'; +import { skipOnboarding as skipOnboardingAction } from '../../../store/users'; import { CurrentUser, IdentityProvider, isLoggedIn, LoggedInUser } from '../../../app/types'; import { skipOnboarding, getIdentityProviders } from '../../../api/users'; import { translate } from '../../../helpers/l10n'; @@ -212,13 +212,13 @@ export class CreateProjectPage extends React.PureComponent<Props, State> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ currentUser: getCurrentUser(state) }); const mapDispatchToProps: DispatchProps = { addGlobalErrorMessage, skipOnboardingAction }; -export default connect<StateProps, DispatchProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(CreateProjectPage); diff --git a/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx b/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx index 299dc7676e0..f2e63f08650 100644 --- a/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx @@ -25,7 +25,7 @@ import Select from '../../../components/controls/Select'; import { Button, SubmitButton } from '../../../components/ui/buttons'; import { LoggedInUser, Organization } from '../../../app/types'; import { fetchMyOrganizations } from '../../account/organizations/actions'; -import { getMyOrganizations } from '../../../store/rootReducer'; +import { getMyOrganizations, Store } from '../../../store/rootReducer'; import { translate } from '../../../helpers/l10n'; import { createProject } from '../../../api/components'; import DeferredSpinner from '../../../components/common/DeferredSpinner'; @@ -217,12 +217,12 @@ const mapDispatchToProps = ({ fetchMyOrganizations } as any) as DispatchProps; -const mapStateToProps = (state: any): StateProps => { +const mapStateToProps = (state: Store): StateProps => { return { userOrganizations: getMyOrganizations(state) }; }; -export default connect<StateProps, DispatchProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(ManualProjectCreate); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx index ada03f39f0a..33229e381b7 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx @@ -23,7 +23,7 @@ import Filter from './Filter'; import FilterHeader from './FilterHeader'; import SearchableFilterFooter from './SearchableFilterFooter'; import SearchableFilterOption from './SearchableFilterOption'; -import { getLanguageByKey, Languages } from '../../../store/languages/reducer'; +import { getLanguageByKey, Languages } from '../../../store/languages'; import { translate } from '../../../helpers/l10n'; import { Facet } from '../types'; import { RawQuery } from '../../../helpers/query'; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilterContainer.tsx b/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilterContainer.tsx index 43d9eb3d6b2..2b5daab2df7 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilterContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilterContainer.tsx @@ -19,15 +19,10 @@ */ import { connect } from 'react-redux'; import LanguagesFilter from './LanguagesFilter'; -import { Languages } from '../../../store/languages/reducer'; -import { getLanguages } from '../../../store/rootReducer'; +import { getLanguages, Store } from '../../../store/rootReducer'; -interface StateProps { - languages: Languages; -} - -const stateToProps = (state: any) => ({ +const stateToProps = (state: Store) => ({ languages: getLanguages(state) }); -export default connect<StateProps>(stateToProps)(LanguagesFilter); +export default connect(stateToProps)(LanguagesFilter); diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/Visualizations.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/Visualizations.tsx index 947b58fddde..f5c8c5e612a 100644 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/Visualizations.tsx +++ b/server/sonar-web/src/main/js/apps/projects/visualizations/Visualizations.tsx @@ -29,7 +29,7 @@ import { Project } from '../types'; import { translate, translateWithParameters } from '../../../helpers/l10n'; interface Props { - displayOrganizations: boolean; + displayOrganizations?: boolean; projects: Project[]; sort?: string; total?: number; diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/AppContainer.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/AppContainer.tsx index 30f543f096d..b7ac3c91a5a 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/AppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/AppContainer.tsx @@ -22,8 +22,8 @@ import { connect } from 'react-redux'; import App from './App'; import forSingleOrganization from '../organizations/forSingleOrganization'; import { Organization, LoggedInUser, Visibility } from '../../app/types'; -import { getAppState, getOrganizationByKey, getCurrentUser } from '../../store/rootReducer'; -import { receiveOrganizations } from '../../store/organizations/duck'; +import { getAppState, getOrganizationByKey, getCurrentUser, Store } from '../../store/rootReducer'; +import { receiveOrganizations } from '../../store/organizations'; import { changeProjectDefaultVisibility } from '../../api/permissions'; import { fetchOrganization } from '../organizations/actions'; @@ -40,6 +40,7 @@ interface DispatchProps { interface OwnProps { onRequestFail: (error: any) => void; + organization: Organization; } class AppContainer extends React.PureComponent<OwnProps & StateProps & DispatchProps> { @@ -78,7 +79,7 @@ class AppContainer extends React.PureComponent<OwnProps & StateProps & DispatchP } } -const mapStateToProps = (state: any, ownProps: any) => ({ +const mapStateToProps = (state: Store, ownProps: OwnProps) => ({ appState: getAppState(state), currentUser: getCurrentUser(state) as LoggedInUser, organization: @@ -102,7 +103,7 @@ const mapDispatchToProps = (dispatch: Function) => ({ }); export default forSingleOrganization( - connect<StateProps, DispatchProps, OwnProps>( + connect( mapStateToProps, mapDispatchToProps )(AppContainer) diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsApp.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsApp.tsx index d22d36f9c7d..d09415b9c64 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsApp.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsApp.tsx @@ -23,7 +23,7 @@ import Helmet from 'react-helmet'; import { connect } from 'react-redux'; import DetailsHeader from './DetailsHeader'; import DetailsContent from './DetailsContent'; -import { getMetrics } from '../../../store/rootReducer'; +import { getMetrics, Store } from '../../../store/rootReducer'; import { fetchMetrics } from '../../../store/rootActions'; import { fetchQualityGate } from '../../../api/quality-gates'; import { Metric, QualityGate, Condition } from '../../../app/types'; @@ -170,11 +170,11 @@ export class DetailsApp extends React.PureComponent<Props, State> { const mapDispatchToProps: DispatchToProps = { fetchMetrics }; -const mapStateToProps = (state: any): StateToProps => ({ +const mapStateToProps = (state: Store): StateToProps => ({ metrics: getMetrics(state) }); -export default connect<StateToProps, DispatchToProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(DetailsApp); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx index 67697a9c4f8..5fa5abf6642 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx @@ -24,13 +24,12 @@ import { sortProfiles } from '../utils'; import { Exporter, Profile } from '../types'; import OrganizationHelmet from '../../../components/common/OrganizationHelmet'; import { translate } from '../../../helpers/l10n'; -import { Languages } from '../../../store/languages/reducer'; +import { Languages } from '../../../store/languages'; import '../styles.css'; interface Props { children: React.ReactElement<any>; languages: Languages; - onRequestFail: (reasong: any) => void; organization: { name: string; key: string } | undefined; } @@ -103,7 +102,6 @@ export default class App extends React.PureComponent<Props, State> { languages: finalLanguages, exporters: this.state.exporters, updateProfiles: this.updateProfiles, - onRequestFail: this.props.onRequestFail, organization: organization ? organization.key : null }); } diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/AppContainer.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/AppContainer.tsx index 417c54699d6..525f5af615d 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/components/AppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/AppContainer.tsx @@ -20,33 +20,13 @@ import { connect } from 'react-redux'; import App from './App'; import forSingleOrganization from '../../organizations/forSingleOrganization'; -import { getLanguages, getOrganizationByKey } from '../../../store/rootReducer'; -import { onFail } from '../../../store/rootActions'; -import { Languages } from '../../../store/languages/reducer'; +import { getLanguages, getOrganizationByKey, Store } from '../../../store/rootReducer'; -interface StateProps { - languages: Languages; - organization: { name: string; key: string } | undefined; -} - -interface DispatchProps { - onRequestFail: (reasong: any) => void; -} - -const mapStateToProps = (state: any, ownProps: any) => ({ +const mapStateToProps = (state: Store, ownProps: any) => ({ languages: getLanguages(state), organization: ownProps.params.organizationKey ? getOrganizationByKey(state, ownProps.params.organizationKey) : undefined }); -const mapDispatchToProps = (dispatch: any) => ({ - onRequestFail: (error: any) => onFail(dispatch)(error) -}); - -export default forSingleOrganization( - connect<StateProps, DispatchProps>( - mapStateToProps, - mapDispatchToProps - )(App) -); +export default forSingleOrganization(connect(mapStateToProps)(App)); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/CopyProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/CopyProfileForm.tsx index 39cd96b4c88..d26262e3e47 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/components/CopyProfileForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/CopyProfileForm.tsx @@ -27,7 +27,6 @@ import { translate, translateWithParameters } from '../../../helpers/l10n'; interface Props { onClose: () => void; onCopy: (name: string) => void; - onRequestFail: (reasong: any) => void; profile: Profile; } @@ -61,11 +60,10 @@ export default class CopyProfileForm extends React.PureComponent<Props, State> { this.setState({ loading: true }); copyProfile(this.props.profile.key, name).then( (profile: any) => this.props.onCopy(profile.name), - (error: any) => { + () => { if (this.mounted) { this.setState({ loading: false }); } - this.props.onRequestFail(error); } ); } diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/DeleteProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/DeleteProfileForm.tsx index 39260d39eb7..941d82c311f 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/components/DeleteProfileForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/DeleteProfileForm.tsx @@ -27,7 +27,6 @@ import { translate, translateWithParameters } from '../../../helpers/l10n'; interface Props { onClose: () => void; onDelete: () => void; - onRequestFail: (reason: any) => void; profile: Profile; } @@ -51,11 +50,10 @@ export default class DeleteProfileForm extends React.PureComponent<Props, State> handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => { event.preventDefault(); this.setState({ loading: true }); - deleteProfile(this.props.profile.key).then(this.props.onDelete, (error: any) => { + deleteProfile(this.props.profile.key).then(this.props.onDelete, () => { if (this.mounted) { this.setState({ loading: false }); } - this.props.onRequestFail(error); }); }; diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.tsx index c4b3566803e..ac464d475c8 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.tsx @@ -35,7 +35,6 @@ import ActionsDropdown, { interface Props { className?: string; fromList?: boolean; - onRequestFail: (reasong: any) => void; organization: string | null; profile: Profile; updateProfiles: () => Promise<void>; @@ -198,7 +197,6 @@ export default class ProfileActions extends React.PureComponent<Props, State> { <CopyProfileForm onClose={this.closeCopyForm} onCopy={this.handleProfileCopy} - onRequestFail={this.props.onRequestFail} profile={profile} /> )} @@ -207,7 +205,6 @@ export default class ProfileActions extends React.PureComponent<Props, State> { <DeleteProfileForm onClose={this.closeDeleteForm} onDelete={this.handleProfileDelete} - onRequestFail={this.props.onRequestFail} profile={profile} /> )} @@ -216,7 +213,6 @@ export default class ProfileActions extends React.PureComponent<Props, State> { <RenameProfileForm onClose={this.closeRenameForm} onRename={this.handleProfileRename} - onRequestFail={this.props.onRequestFail} profile={profile} /> )} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.tsx index 40294051be5..f8f1fdfacad 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.tsx @@ -30,7 +30,6 @@ interface Props { pathname: string; query: { key?: string; language: string; name: string }; }; - onRequestFail: (reasong: any) => void; organization: string | null; profiles: Profile[]; updateProfiles: () => Promise<void>; @@ -75,7 +74,6 @@ export default class ProfileContainer extends React.PureComponent<Props & WithRo } const child = React.cloneElement(this.props.children, { - onRequestFail: this.props.onRequestFail, organization, profile, profiles, @@ -86,7 +84,6 @@ export default class ProfileContainer extends React.PureComponent<Props & WithRo <div id="quality-profile"> <Helmet title={profile.name} /> <ProfileHeader - onRequestFail={this.props.onRequestFail} organization={organization} profile={profile} updateProfiles={this.props.updateProfiles} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/RenameProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/RenameProfileForm.tsx index fd04227ede9..f8744737d2d 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/components/RenameProfileForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/RenameProfileForm.tsx @@ -27,7 +27,6 @@ import { translate, translateWithParameters } from '../../../helpers/l10n'; interface Props { onClose: () => void; onRename: (name: string) => void; - onRequestFail: (reason: any) => void; profile: Profile; } @@ -61,11 +60,10 @@ export default class RenameProfileForm extends React.PureComponent<Props, State> this.setState({ loading: true }); renameProfile(this.props.profile.key, name).then( () => this.props.onRename(name), - (error: any) => { + () => { if (this.mounted) { this.setState({ loading: false }); } - this.props.onRequestFail(error); } ); } diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileActions-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileActions-test.tsx index c407c0e64fe..6e12e93f278 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileActions-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileActions-test.tsx @@ -40,14 +40,7 @@ const PROFILE = { it('renders with no permissions', () => { expect( - shallow( - <ProfileActions - onRequestFail={jest.fn()} - organization="org" - profile={PROFILE} - updateProfiles={jest.fn()} - /> - ) + shallow(<ProfileActions organization="org" profile={PROFILE} updateProfiles={jest.fn()} />) ).toMatchSnapshot(); }); @@ -55,7 +48,6 @@ it('renders with permission to edit only', () => { expect( shallow( <ProfileActions - onRequestFail={jest.fn()} organization="org" profile={{ ...PROFILE, actions: { edit: true } }} updateProfiles={jest.fn()} @@ -68,7 +60,6 @@ it('renders with all permissions', () => { expect( shallow( <ProfileActions - onRequestFail={jest.fn()} organization="org" profile={{ ...PROFILE, @@ -91,7 +82,6 @@ it('should copy profile', async () => { const push = jest.fn(); const wrapper = shallow( <ProfileActions - onRequestFail={jest.fn()} organization="org" profile={{ ...PROFILE, actions: { copy: true } }} updateProfiles={updateProfiles} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileContainer-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileContainer-test.tsx index 756b21b6b31..c04577b217b 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileContainer-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileContainer-test.tsx @@ -35,7 +35,6 @@ it('should render ProfileHeader', () => { const output = shallow( <ProfileContainer location={{ pathname: '', query: { language: 'js', name: 'fake' } }} - onRequestFail={jest.fn()} organization={null} profiles={profiles} updateProfiles={updateProfiles} @@ -57,7 +56,6 @@ it('should render ProfileNotFound', () => { const output = shallow( <ProfileContainer location={{ pathname: '', query: { language: 'js', name: 'random' } }} - onRequestFail={jest.fn()} organization={null} profiles={profiles} updateProfiles={jest.fn()} @@ -74,7 +72,6 @@ it('should render Helmet', () => { const output = shallow( <ProfileContainer location={{ pathname: '', query: { language: 'js', name: 'First Profile' } }} - onRequestFail={jest.fn()} organization={null} profiles={profiles} updateProfiles={updateProfiles} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx index b783eb7e411..af740ec35a4 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx @@ -29,7 +29,6 @@ import { translate } from '../../../helpers/l10n'; interface Props { onChange: () => void; onClose: () => void; - onRequestFail: (reasong: any) => void; profile: Profile; profiles: Profile[]; } @@ -67,11 +66,10 @@ export default class ChangeParentForm extends React.PureComponent<Props, State> this.setState({ loading: true }); changeProfileParent(this.props.profile.key, parent) .then(this.props.onChange) - .catch((error: any) => { + .catch(() => { if (this.mounted) { this.setState({ loading: false }); } - this.props.onRequestFail(error); }); } }; diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.tsx index 62cc3952052..7fa67e0b743 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.tsx @@ -27,7 +27,6 @@ import { Exporter, Profile } from '../types'; interface Props { exporters: Exporter[]; - onRequestFail: (reasong: any) => void; organization: string | null; profile: Profile; profiles: Profile[]; diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileHeader.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileHeader.tsx index 2315bfcb57b..06dfba05ee2 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileHeader.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileHeader.tsx @@ -33,7 +33,6 @@ import { import { Profile } from '../types'; interface Props { - onRequestFail: (reasong: any) => void; profile: Profile; organization: string | null; updateProfiles: () => Promise<void>; @@ -111,7 +110,6 @@ export default class ProfileHeader extends React.PureComponent<Props> { <li> <ProfileActions className="pull-left" - onRequestFail={this.props.onRequestFail} organization={organization} profile={profile} updateProfiles={this.props.updateProfiles} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx index 85deb056f70..811d248495c 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx @@ -27,7 +27,6 @@ import { Button } from '../../../components/ui/buttons'; import { translate } from '../../../helpers/l10n'; interface Props { - onRequestFail: (reason: any) => void; organization: string | null; profile: Profile; profiles: Profile[]; @@ -192,7 +191,6 @@ export default class ProfileInheritance extends React.PureComponent<Props, State <ChangeParentForm onChange={this.handleParentChange} onClose={this.closeForm} - onRequestFail={this.props.onRequestFail} profile={profile} profiles={profiles.filter(p => p !== profile && p.language === profile.language)} /> diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileDetails-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileDetails-test.tsx index ed4b88c7c34..38d2cb8e0d7 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileDetails-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileDetails-test.tsx @@ -27,7 +27,6 @@ it('renders without permissions', () => { shallow( <ProfileDetails exporters={[]} - onRequestFail={jest.fn()} organization="org" profile={{} as Profile} profiles={[]} @@ -42,7 +41,6 @@ it('renders with edit permission', () => { shallow( <ProfileDetails exporters={[]} - onRequestFail={jest.fn()} organization="org" profile={{ actions: { edit: true } } as Profile} profiles={[]} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileDetails-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileDetails-test.tsx.snap index 57001b3e68d..9f37d14f9e2 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileDetails-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileDetails-test.tsx.snap @@ -10,7 +10,6 @@ exports[`renders with edit permission 1`] = ` > <ProfileRules exporters={Array []} - onRequestFail={[MockFunction]} organization="org" profile={ Object { @@ -24,7 +23,6 @@ exports[`renders with edit permission 1`] = ` /> <ProfileExporters exporters={Array []} - onRequestFail={[MockFunction]} organization="org" profile={ Object { @@ -52,7 +50,6 @@ exports[`renders with edit permission 1`] = ` > <ProfileInheritance exporters={Array []} - onRequestFail={[MockFunction]} organization="org" profile={ Object { @@ -66,7 +63,6 @@ exports[`renders with edit permission 1`] = ` /> <ProfileProjects exporters={Array []} - onRequestFail={[MockFunction]} organization="org" profile={ Object { @@ -93,7 +89,6 @@ exports[`renders without permissions 1`] = ` > <ProfileRules exporters={Array []} - onRequestFail={[MockFunction]} organization="org" profile={Object {}} profiles={Array []} @@ -101,7 +96,6 @@ exports[`renders without permissions 1`] = ` /> <ProfileExporters exporters={Array []} - onRequestFail={[MockFunction]} organization="org" profile={Object {}} profiles={Array []} @@ -113,7 +107,6 @@ exports[`renders without permissions 1`] = ` > <ProfileInheritance exporters={Array []} - onRequestFail={[MockFunction]} organization="org" profile={Object {}} profiles={Array []} @@ -121,7 +114,6 @@ exports[`renders without permissions 1`] = ` /> <ProfileProjects exporters={Array []} - onRequestFail={[MockFunction]} organization="org" profile={Object {}} profiles={Array []} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/CreateProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/CreateProfileForm.tsx index e9fcc95b3ad..388675ba4d4 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/CreateProfileForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/CreateProfileForm.tsx @@ -29,7 +29,6 @@ interface Props { languages: Array<{ key: string; name: string }>; onClose: () => void; onCreate: Function; - onRequestFail: (reasong: any) => void; organization: string | null; } @@ -89,11 +88,10 @@ export default class CreateProfileForm extends React.PureComponent<Props, State> createQualityProfile(data).then( (response: any) => this.props.onCreate(response.profile), - (error: any) => { + () => { if (this.mounted) { this.setState({ loading: false }); } - this.props.onRequestFail(error); } ); }; diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/HomeContainer.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/HomeContainer.tsx index af78f87f44e..201eedb5164 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/HomeContainer.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/HomeContainer.tsx @@ -28,7 +28,6 @@ interface Props { actions: Actions; languages: Array<{ key: string; name: string }>; location: { query: { [p: string]: string } }; - onRequestFail: (reason: any) => void; organization: string | null; profiles: Profile[]; updateProfiles: () => Promise<void>; diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx index 4bfb1c02c77..d064cfb708c 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx @@ -31,7 +31,6 @@ import { translate } from '../../../helpers/l10n'; interface Props { actions: Actions; languages: Array<{ key: string; name: string }>; - onRequestFail: (reason: any) => void; organization: string | null; updateProfiles: () => Promise<void>; } @@ -112,7 +111,6 @@ export default class PageHeader extends React.PureComponent<Props, State> { {this.state.restoreFormOpen && ( <RestoreProfileForm onClose={this.closeRestoreForm} - onRequestFail={this.props.onRequestFail} onRestore={this.props.updateProfiles} organization={this.props.organization} /> @@ -123,7 +121,6 @@ export default class PageHeader extends React.PureComponent<Props, State> { languages={this.props.languages} onClose={this.closeCreateForm} onCreate={this.handleCreate} - onRequestFail={this.props.onRequestFail} organization={this.props.organization} /> )} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx index 05faaa8ef8f..599c0f398d8 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx @@ -28,7 +28,6 @@ import { Profile } from '../types'; interface Props { languages: Array<{ key: string; name: string }>; location: { query: { [p: string]: string } }; - onRequestFail: (reason: any) => void; organization: string | null; profiles: Profile[]; updateProfiles: () => Promise<void>; @@ -39,7 +38,6 @@ export default class ProfilesList extends React.PureComponent<Props> { return profiles.map(profile => ( <ProfilesListRow key={profile.key} - onRequestFail={this.props.onRequestFail} organization={this.props.organization} profile={profile} updateProfiles={this.props.updateProfiles} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx index 5fb2c5e1fac..682ede61e62 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx @@ -31,7 +31,6 @@ import Tooltip from '../../../components/controls/Tooltip'; import DocTooltip from '../../../components/docs/DocTooltip'; interface Props { - onRequestFail: (reason: any) => void; organization: string | null; profile: Profile; updateProfiles: () => Promise<void>; @@ -149,7 +148,6 @@ export default class ProfilesListRow extends React.PureComponent<Props> { <td className="quality-profiles-table-actions thin nowrap text-middle text-right"> <ProfileActions fromList={true} - onRequestFail={this.props.onRequestFail} organization={this.props.organization} profile={this.props.profile} updateProfiles={this.props.updateProfiles} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx index a93f0e0a44e..ce22a7a15fa 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx @@ -25,7 +25,6 @@ import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons'; interface Props { onClose: () => void; - onRequestFail: (reason: any) => void; onRestore: () => void; organization: string | null; } @@ -71,11 +70,10 @@ export default class RestoreProfileForm extends React.PureComponent<Props, State } this.props.onRestore(); }, - (error: any) => { + () => { if (this.mounted) { this.setState({ loading: false }); } - this.props.onRequestFail(error); } ); }; diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx b/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx index ed4c7dacfe9..a51599f362c 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx @@ -116,7 +116,7 @@ class LoginContainer extends React.PureComponent<Props, State> { const mapStateToProps = null; const mapDispatchToProps = { doLogin: doLogin as any }; -export default connect<{}, DispatchToProps, OwnProps>( +export default connect( mapStateToProps, mapDispatchToProps )(LoginContainer); diff --git a/server/sonar-web/src/main/js/apps/settings/store/actions.js b/server/sonar-web/src/main/js/apps/settings/store/actions.js index d4d1dddd806..34bdf549004 100644 --- a/server/sonar-web/src/main/js/apps/settings/store/actions.js +++ b/server/sonar-web/src/main/js/apps/settings/store/actions.js @@ -29,7 +29,7 @@ import { resetSettingValue } from '../../../api/settings'; import { parseError } from '../../../helpers/request'; -import { addGlobalErrorMessage, closeAllGlobalMessages } from '../../../store/globalMessages/duck'; +import { addGlobalErrorMessage, closeAllGlobalMessages } from '../../../store/globalMessages'; import { isEmptyValue } from '../utils'; import { translate } from '../../../helpers/l10n'; import { getSettingsAppDefinition, getSettingsAppChangedValue } from '../../../store/rootReducer'; diff --git a/server/sonar-web/src/main/js/apps/settings/store/encryptionPage/actions.js b/server/sonar-web/src/main/js/apps/settings/store/encryptionPage/actions.js index 55ce9d6756d..f20e9e91c90 100644 --- a/server/sonar-web/src/main/js/apps/settings/store/encryptionPage/actions.js +++ b/server/sonar-web/src/main/js/apps/settings/store/encryptionPage/actions.js @@ -22,7 +22,7 @@ import { parseError } from '../../../../helpers/request'; import { addGlobalErrorMessage, closeAllGlobalMessages -} from '../../../../store/globalMessages/duck'; +} from '../../../../store/globalMessages'; export const UPDATE_ENCRYPTION = 'UPDATE_ENCRYPTION'; diff --git a/server/sonar-web/src/main/js/apps/settings/store/rootReducer.js b/server/sonar-web/src/main/js/apps/settings/store/rootReducer.js index 13320969836..37f7f1ecd56 100644 --- a/server/sonar-web/src/main/js/apps/settings/store/rootReducer.js +++ b/server/sonar-web/src/main/js/apps/settings/store/rootReducer.js @@ -23,8 +23,8 @@ import definitions, * as fromDefinitions from './definitions/reducer'; import encryptionPage from './encryptionPage/reducer'; import values, * as fromValues from './values/reducer'; import settingsPage, * as fromSettingsPage from './settingsPage/reducer'; -import globalMessages, * as fromGlobalMessages from '../../../store/globalMessages/duck'; -/*:: import type { State as GlobalMessagesState } from '../../../store/globalMessages/duck'; */ +import globalMessages, * as fromGlobalMessages from '../../../store/globalMessages'; +/*:: import type { State as GlobalMessagesState } from '../../../store/globalMessages'; */ /*:: import type { State as ValuesState } from './values/reducer'; */ /*:: diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx index b8006ff3758..1ed6b84045e 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx @@ -27,7 +27,7 @@ import OnboardingTeamIcon from '../../../components/icons-components/OnboardingT import { Button, ResetButtonLink } from '../../../components/ui/buttons'; import { translate } from '../../../helpers/l10n'; import { CurrentUser, isLoggedIn } from '../../../app/types'; -import { getCurrentUser } from '../../../store/rootReducer'; +import { getCurrentUser, Store } from '../../../store/rootReducer'; import '../styles.css'; interface OwnProps { @@ -94,6 +94,6 @@ export class OnboardingModal extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any): StateProps => ({ currentUser: getCurrentUser(state) }); +const mapStateToProps = (state: Store): StateProps => ({ currentUser: getCurrentUser(state) }); -export default connect<StateProps, {}, OwnProps>(mapStateToProps)(OnboardingModal); +export default connect(mapStateToProps)(OnboardingModal); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx index cd5bc33f08c..2d6901b63c9 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx @@ -22,7 +22,7 @@ import * as PropTypes from 'prop-types'; import { connect } from 'react-redux'; import OnboardingModal from './OnboardingModal'; import { skipOnboarding } from '../../../api/users'; -import { skipOnboarding as skipOnboardingAction } from '../../../store/users/actions'; +import { skipOnboarding as skipOnboardingAction } from '../../../store/users'; import CreateOrganizationForm from '../../account/organizations/CreateOrganizationForm'; import TeamOnboardingModal from '../teamOnboarding/TeamOnboardingModal'; import { Organization } from '../../../app/types'; @@ -96,7 +96,7 @@ export class OnboardingPage extends React.PureComponent<DispatchProps, State> { const mapDispatchToProps: DispatchProps = { skipOnboardingAction }; -export default connect<{}, DispatchProps>( +export default connect( null, mapDispatchToProps )(OnboardingPage); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboarding.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboarding.tsx index e3511631aa4..9068fb81f94 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboarding.tsx +++ b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboarding.tsx @@ -26,7 +26,7 @@ import ProjectAnalysisStep from '../components/ProjectAnalysisStep'; import OrganizationStep from '../components/OrganizationStep'; import TokenStep from '../components/TokenStep'; import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication'; -import { getCurrentUser, areThereCustomOrganizations } from '../../../store/rootReducer'; +import { getCurrentUser, areThereCustomOrganizations, Store } from '../../../store/rootReducer'; import { CurrentUser, isLoggedIn } from '../../../app/types'; import { ResetButtonLink } from '../../../components/ui/buttons'; import { getProjectUrl } from '../../../helpers/urls'; @@ -41,7 +41,7 @@ interface OwnProps { interface StateProps { currentUser: CurrentUser; - organizationsEnabled: boolean; + organizationsEnabled?: boolean; } type Props = OwnProps & StateProps; @@ -196,11 +196,11 @@ export class ProjectOnboarding extends React.PureComponent<Props, State> { } } -const mapStateToProps = (state: any): StateProps => { +const mapStateToProps = (state: Store): StateProps => { return { currentUser: getCurrentUser(state), organizationsEnabled: areThereCustomOrganizations(state) }; }; -export default connect<StateProps, {}, OwnProps>(mapStateToProps)(ProjectOnboarding); +export default connect(mapStateToProps)(ProjectOnboarding); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboardingPage.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboardingPage.tsx index e3e747805fc..d22ab7bcf52 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboardingPage.tsx +++ b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboardingPage.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import * as PropTypes from 'prop-types'; import { connect } from 'react-redux'; import ProjectOnboardingModal from './ProjectOnboardingModal'; -import { skipOnboarding } from '../../../store/users/actions'; +import { skipOnboarding } from '../../../store/users'; interface DispatchProps { skipOnboarding: () => void; @@ -44,7 +44,7 @@ export class ProjectOnboardingPage extends React.PureComponent<DispatchProps> { const mapDispatchToProps: DispatchProps = { skipOnboarding }; -export default connect<{}, DispatchProps>( +export default connect( null, mapDispatchToProps )(ProjectOnboardingPage); diff --git a/server/sonar-web/src/main/js/apps/users/UsersApp.tsx b/server/sonar-web/src/main/js/apps/users/UsersApp.tsx index edefebb1086..9c898e36ad6 100644 --- a/server/sonar-web/src/main/js/apps/users/UsersApp.tsx +++ b/server/sonar-web/src/main/js/apps/users/UsersApp.tsx @@ -34,7 +34,7 @@ import { translate } from '../../helpers/l10n'; interface Props { currentUser: { isLoggedIn: boolean; login?: string }; location: Location; - organizationsEnabled: boolean; + organizationsEnabled?: boolean; } interface State { diff --git a/server/sonar-web/src/main/js/apps/users/UsersAppContainer.tsx b/server/sonar-web/src/main/js/apps/users/UsersAppContainer.tsx index 47fdd0afb3a..563ed0cfd21 100644 --- a/server/sonar-web/src/main/js/apps/users/UsersAppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/users/UsersAppContainer.tsx @@ -18,22 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; -import { Location } from 'history'; import UsersApp from './UsersApp'; -import { areThereCustomOrganizations, getCurrentUser } from '../../store/rootReducer'; +import { areThereCustomOrganizations, getCurrentUser, Store } from '../../store/rootReducer'; -interface OwnProps { - location: Location; -} - -interface StateToProps { - currentUser: { isLoggedIn: boolean; login?: string }; - organizationsEnabled: boolean; -} - -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ currentUser: getCurrentUser(state), organizationsEnabled: areThereCustomOrganizations(state) }); -export default connect<StateToProps, {}, OwnProps>(mapStateToProps)(UsersApp); +export default connect(mapStateToProps)(UsersApp); diff --git a/server/sonar-web/src/main/js/apps/users/UsersList.tsx b/server/sonar-web/src/main/js/apps/users/UsersList.tsx index 8888af81c51..cb91c04a60a 100644 --- a/server/sonar-web/src/main/js/apps/users/UsersList.tsx +++ b/server/sonar-web/src/main/js/apps/users/UsersList.tsx @@ -26,7 +26,7 @@ interface Props { currentUser: { isLoggedIn: boolean; login?: string }; identityProviders: IdentityProvider[]; onUpdateUsers: () => void; - organizationsEnabled: boolean; + organizationsEnabled?: boolean; updateTokensCount: (login: string, tokensCount: number) => void; users: User[]; } diff --git a/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx b/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx index 33562848989..10d34f4a158 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx @@ -33,7 +33,7 @@ interface Props { identityProvider?: IdentityProvider; isCurrentUser: boolean; onUpdateUsers: () => void; - organizationsEnabled: boolean; + organizationsEnabled?: boolean; updateTokensCount: (login: string, tokensCount: number) => void; user: User; } diff --git a/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx b/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx index 457bc24c4ea..9c4fbe34a9a 100644 --- a/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx +++ b/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx @@ -18,16 +18,16 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { find, sortBy } from 'lodash'; +import { sortBy } from 'lodash'; import Histogram from './Histogram'; import { formatMeasure } from '../../helpers/measures'; -import { Language } from '../../api/languages'; import { translate } from '../../helpers/l10n'; +import { Languages } from '../../store/languages'; interface Props { alignTicks?: boolean; distribution: string; - languages?: Language[]; + languages: Languages; width: number; } @@ -61,7 +61,7 @@ export default function LanguageDistribution(props: Props) { if (langKey === '<null>') { return translate('unknown'); } - const lang = find(props.languages, { key: langKey }); + const lang = props.languages[langKey]; return lang ? lang.name : langKey; } } diff --git a/server/sonar-web/src/main/js/components/charts/LanguageDistributionContainer.tsx b/server/sonar-web/src/main/js/components/charts/LanguageDistributionContainer.tsx index 9ef2039202e..abbf2a645b8 100644 --- a/server/sonar-web/src/main/js/components/charts/LanguageDistributionContainer.tsx +++ b/server/sonar-web/src/main/js/components/charts/LanguageDistributionContainer.tsx @@ -19,10 +19,10 @@ */ import { connect } from 'react-redux'; import LanguageDistribution from './LanguageDistribution'; -import { getLanguages } from '../../store/rootReducer'; +import { getLanguages, Store } from '../../store/rootReducer'; -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ languages: getLanguages(state) }); -export default connect<any, any, any>(mapStateToProps)(LanguageDistribution); +export default connect(mapStateToProps)(LanguageDistribution); diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx b/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx index 224244ca51c..bf544029f25 100644 --- a/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx +++ b/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx @@ -26,7 +26,7 @@ it('renders', () => { shallow( <LanguageDistribution distribution="java=1734;js=845;cpp=73;<null>=15" - languages={[{ key: 'java', name: 'Java' }, { key: 'js', name: 'JavaScript' }]} + languages={{ java: { key: 'java', name: 'Java' }, js: { key: 'js', name: 'JavaScript' } }} width={100} /> ) diff --git a/server/sonar-web/src/main/js/components/common/PrivacyBadgeContainer.tsx b/server/sonar-web/src/main/js/components/common/PrivacyBadgeContainer.tsx index 2c702af7c02..1a72a92c354 100644 --- a/server/sonar-web/src/main/js/components/common/PrivacyBadgeContainer.tsx +++ b/server/sonar-web/src/main/js/components/common/PrivacyBadgeContainer.tsx @@ -26,7 +26,12 @@ import { translate } from '../../helpers/l10n'; import { Visibility, Organization, CurrentUser } from '../../app/types'; import { isSonarCloud } from '../../helpers/system'; import { isCurrentUserMemberOf, isPaidOrganization } from '../../helpers/organizations'; -import { getCurrentUser, getOrganizationByKey, getMyOrganizations } from '../../store/rootReducer'; +import { + getCurrentUser, + getOrganizationByKey, + getMyOrganizations, + Store +} from '../../store/rootReducer'; import VisibleIcon from '../icons-components/VisibleIcon'; import DocTooltip from '../docs/DocTooltip'; @@ -99,7 +104,7 @@ export function PrivacyBadge({ ); } -const mapStateToProps = (state: any, { organization }: OwnProps) => { +const mapStateToProps = (state: Store, { organization }: OwnProps) => { if (typeof organization === 'string') { organization = getOrganizationByKey(state, organization); } @@ -110,7 +115,7 @@ const mapStateToProps = (state: any, { organization }: OwnProps) => { }; }; -export default connect<StateToProps, {}, OwnProps>(mapStateToProps)(PrivacyBadge); +export default connect(mapStateToProps)(PrivacyBadge); function getDoc(visibility: Visibility, icon: JSX.Element | null, organization: Organization) { let doc; diff --git a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx index d71cec022b5..5be1bbc5816 100644 --- a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx +++ b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx @@ -24,8 +24,8 @@ import Tooltip from './Tooltip'; import HomeIcon from '../icons-components/HomeIcon'; import { CurrentUser, isLoggedIn, HomePage, isSameHomePage } from '../../app/types'; import { translate } from '../../helpers/l10n'; -import { getCurrentUser } from '../../store/rootReducer'; -import { setHomePage } from '../../store/users/actions'; +import { getCurrentUser, Store } from '../../store/rootReducer'; +import { setHomePage } from '../../store/users'; interface StateProps { currentUser: CurrentUser; @@ -81,7 +81,7 @@ class HomePageSelect extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any): StateProps => ({ +const mapStateToProps = (state: Store): StateProps => ({ currentUser: getCurrentUser(state) }); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx index 4d5af634c91..89803a78e97 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx +++ b/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx @@ -21,9 +21,9 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import HomePageSelect from '../HomePageSelect'; import { setHomePage } from '../../../api/users'; -import { HomePageType, HomePage, LoggedInUser } from '../../../app/types'; +import { HomePageType, HomePage, LoggedInUser, CurrentUser } from '../../../app/types'; import { click } from '../../../helpers/testUtils'; -import rootReducer, { getCurrentUser } from '../../../store/rootReducer'; +import rootReducer, { getCurrentUser, Store } from '../../../store/rootReducer'; import configureStore from '../../../store/utils/configureStore'; jest.mock('../../../api/users', () => ({ @@ -33,29 +33,35 @@ jest.mock('../../../api/users', () => ({ const homepage: HomePage = { type: HomePageType.Projects }; it('should render unchecked', () => { - const store = configureStore(rootReducer, { users: { currentUser: { isLoggedIn: true } } }); + const store = configureStore(rootReducer, { + users: { currentUser: { isLoggedIn: true } } + } as Store); expect(getWrapper(homepage, store)).toMatchSnapshot(); }); it('should render checked', () => { const store = configureStore(rootReducer, { - users: { currentUser: { isLoggedIn: true, homepage } } - }); + users: { currentUser: { isLoggedIn: true, homepage } as CurrentUser } + } as Store); expect(getWrapper(homepage, store)).toMatchSnapshot(); }); it('should set new home page', async () => { - const store = configureStore(rootReducer, { users: { currentUser: { isLoggedIn: true } } }); + const store = configureStore(rootReducer, { + users: { currentUser: { isLoggedIn: true } } + } as Store); const wrapper = getWrapper(homepage, store); click(wrapper.find('a')); await new Promise(setImmediate); - const currentUser = getCurrentUser(store.getState()) as LoggedInUser; + const currentUser = getCurrentUser(store.getState() as Store) as LoggedInUser; expect(currentUser.homepage).toEqual(homepage); expect(setHomePage).toBeCalledWith(homepage); }); it('should not render for anonymous', () => { - const store = configureStore(rootReducer, { users: { currentUser: { isLoggedIn: false } } }); + const store = configureStore(rootReducer, { + users: { currentUser: { isLoggedIn: false } } + } as Store); expect(getWrapper(homepage, store).type()).toBeNull(); }); diff --git a/server/sonar-web/src/main/js/components/issue/Issue.js b/server/sonar-web/src/main/js/components/issue/Issue.js index 0ea3dedee6e..3562a3c6bad 100644 --- a/server/sonar-web/src/main/js/components/issue/Issue.js +++ b/server/sonar-web/src/main/js/components/issue/Issue.js @@ -23,7 +23,6 @@ import key from 'keymaster'; import PropTypes from 'prop-types'; import IssueView from './IssueView'; import { updateIssue } from './actions'; -import { onFail } from '../../store/rootActions'; import { setIssueAssignee } from '../../api/issues'; /*:: import type { Issue as IssueType } from './types'; */ import './Issue.css'; @@ -135,19 +134,11 @@ export default class Issue extends React.PureComponent { handleAssignement = (login /*: string */) => { const { issue } = this.props; if (issue.assignee !== login) { - updateIssue( - this.props.onChange, - this.handleFail, - setIssueAssignee({ issue: issue.key, assignee: login }) - ); + updateIssue(this.props.onChange, setIssueAssignee({ issue: issue.key, assignee: login })); } this.togglePopup('assign', false); }; - handleFail = (error /*: Error */) => { - onFail(this.context.store.dispatch)(error); - }; - render() { return ( <IssueView @@ -161,7 +152,6 @@ export default class Issue extends React.PureComponent { onChange={this.props.onChange} onCheck={this.props.onCheck} onClick={this.props.onClick} - onFail={this.handleFail} onFilter={this.props.onFilter} selected={this.props.selected} togglePopup={this.togglePopup} diff --git a/server/sonar-web/src/main/js/components/issue/IssueView.js b/server/sonar-web/src/main/js/components/issue/IssueView.js index 100e1942d23..fbb2ac1e259 100644 --- a/server/sonar-web/src/main/js/components/issue/IssueView.js +++ b/server/sonar-web/src/main/js/components/issue/IssueView.js @@ -39,7 +39,6 @@ type Props = {| onChange: Issue => void, onCheck?: (issue: string, event: Event) => void, onClick: string => void, - onFail: Error => void, onFilter?: (property: string, issue: Issue) => void, selected: boolean, togglePopup: (string, boolean | void) => void @@ -64,11 +63,11 @@ export default class IssueView extends React.PureComponent { }; editComment = (comment /*: string */, text /*: string */) => { - updateIssue(this.props.onChange, this.props.onFail, editIssueComment({ comment, text })); + updateIssue(this.props.onChange, editIssueComment({ comment, text })); }; deleteComment = (comment /*: string */) => { - updateIssue(this.props.onChange, this.props.onFail, deleteIssueComment({ comment })); + updateIssue(this.props.onChange, deleteIssueComment({ comment })); }; render() { @@ -94,7 +93,6 @@ export default class IssueView extends React.PureComponent { displayLocationsCount={this.props.displayLocationsCount} displayLocationsLink={this.props.displayLocationsLink} issue={issue} - onFail={this.props.onFail} onFilter={this.props.onFilter} togglePopup={this.props.togglePopup} /> @@ -103,7 +101,6 @@ export default class IssueView extends React.PureComponent { issue={issue} onAssign={this.props.onAssign} onChange={this.props.onChange} - onFail={this.props.onFail} togglePopup={this.props.togglePopup} /> {issue.comments && diff --git a/server/sonar-web/src/main/js/components/issue/actions.js b/server/sonar-web/src/main/js/components/issue/actions.js index 4d3c4c06bd9..567b731c0bb 100644 --- a/server/sonar-web/src/main/js/components/issue/actions.js +++ b/server/sonar-web/src/main/js/components/issue/actions.js @@ -23,7 +23,6 @@ import { parseIssueFromResponse } from '../../helpers/issues'; export const updateIssue = ( onChange /*: Issue => void */, - onFail /*: Error => void */, resultPromise /*: Promise<*> */, oldIssue /*: ?Issue */, newIssue /*: ?Issue */ @@ -47,7 +46,6 @@ export const updateIssue = ( } }, error => { - onFail(error); if (optimisticUpdate) { // $FlowFixMe `oldIssue` is not null, because `optimisticUpdate` is true onChange(oldIssue); diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.js b/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.js index 0f12bf3a226..7167a3a87e2 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.js +++ b/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.js @@ -36,7 +36,6 @@ type Props = { currentPopup: ?string, onAssign: string => void, onChange: Issue => void, - onFail: Error => void, togglePopup: (string, boolean | void) => void }; */ @@ -64,7 +63,6 @@ export default class IssueActionsBar extends React.PureComponent { const newIssue = { ...issue, [property]: value }; updateIssue( this.props.onChange, - this.props.onFail, apiCall({ issue: issue.key, [property]: value }), issue, newIssue @@ -127,7 +125,6 @@ export default class IssueActionsBar extends React.PureComponent { isOpen={this.props.currentPopup === 'transition' && hasTransitions} issue={issue} onChange={this.handleTransition} - onFail={this.props.onFail} togglePopup={this.props.togglePopup} /> </li> @@ -138,7 +135,6 @@ export default class IssueActionsBar extends React.PureComponent { isOpen={this.props.currentPopup === 'assign' && canAssign} issue={issue} onAssign={this.props.onAssign} - onFail={this.props.onFail} togglePopup={this.props.togglePopup} /> </li> @@ -157,7 +153,6 @@ export default class IssueActionsBar extends React.PureComponent { currentPopup={this.props.currentPopup} issueKey={issue.key} onChange={this.props.onChange} - onFail={this.props.onFail} toggleComment={this.toggleComment} /> )} @@ -169,7 +164,6 @@ export default class IssueActionsBar extends React.PureComponent { isOpen={this.props.currentPopup === 'edit-tags' && canSetTags} issue={issue} onChange={this.props.onChange} - onFail={this.props.onFail} togglePopup={this.props.togglePopup} /> </li> diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueAssign.js b/server/sonar-web/src/main/js/components/issue/components/IssueAssign.js index 0eb7f114d70..355b0effbdc 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueAssign.js +++ b/server/sonar-web/src/main/js/components/issue/components/IssueAssign.js @@ -33,7 +33,6 @@ type Props = { issue: Issue, canAssign: boolean, onAssign: string => void, - onFail: Error => void, togglePopup: (string, boolean | void) => void }; */ @@ -78,13 +77,7 @@ export default class IssueAssign extends React.PureComponent { closeOnEscape={true} onRequestClose={this.handleClose} open={this.props.isOpen && this.props.canAssign} - overlay={ - <SetAssigneePopup - issue={this.props.issue} - onFail={this.props.onFail} - onSelect={this.props.onAssign} - /> - }> + overlay={<SetAssigneePopup issue={this.props.issue} onSelect={this.props.onAssign} />}> <Button className="button-link issue-action issue-action-with-options js-issue-assign" onClick={this.toggleAssign}> diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueChangelog.js b/server/sonar-web/src/main/js/components/issue/components/IssueChangelog.js index 0117454c1e9..d071ce91c74 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueChangelog.js +++ b/server/sonar-web/src/main/js/components/issue/components/IssueChangelog.js @@ -33,8 +33,7 @@ type Props = { isOpen: boolean, issue: Issue, creationDate: string, - togglePopup: (string, boolean | void) => void, - onFail: Error => void + togglePopup: (string, boolean | void) => void }; */ @@ -59,7 +58,7 @@ export default class IssueChangelog extends React.PureComponent { <Toggler onRequestClose={this.handleClose} open={this.props.isOpen} - overlay={<ChangelogPopup issue={this.props.issue} onFail={this.props.onFail} />}> + overlay={<ChangelogPopup issue={this.props.issue} />}> <Tooltip mouseEnterDelay={0.5} overlay={<DateTimeFormatter date={this.props.creationDate} />}> diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueCommentAction.js b/server/sonar-web/src/main/js/components/issue/components/IssueCommentAction.js index 5dfd3bfc69d..f40031e0aaf 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueCommentAction.js +++ b/server/sonar-web/src/main/js/components/issue/components/IssueCommentAction.js @@ -33,7 +33,6 @@ type Props = {| currentPopup: ?string, issueKey: string, onChange: Issue => void, - onFail: Error => void, toggleComment: (open?: boolean, placeholder?: string) => void |}; */ @@ -42,11 +41,7 @@ export default class IssueCommentAction extends React.PureComponent { /*:: props: Props; */ addComment = (text /*: string */) => { - updateIssue( - this.props.onChange, - this.props.onFail, - addIssueComment({ issue: this.props.issueKey, text }) - ); + updateIssue(this.props.onChange, addIssueComment({ issue: this.props.issueKey, text })); this.props.toggleComment(false); }; diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTags.js b/server/sonar-web/src/main/js/components/issue/components/IssueTags.js index 00912b7ca81..868126e4d7d 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueTags.js +++ b/server/sonar-web/src/main/js/components/issue/components/IssueTags.js @@ -34,7 +34,6 @@ type Props = {| isOpen: boolean, issue: Issue, onChange: Issue => void, - onFail: Error => void, togglePopup: (string, boolean | void) => void |}; */ @@ -51,7 +50,6 @@ export default class IssueTags extends React.PureComponent { const newIssue = { ...issue, tags }; updateIssue( this.props.onChange, - this.props.onFail, setIssueTags({ issue: issue.key, tags: tags.join(',') }), issue, newIssue diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.js b/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.js index 6c7ab58887a..245240c46c5 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.js +++ b/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.js @@ -40,7 +40,6 @@ type Props = {| displayLocationsCount?: boolean; displayLocationsLink?: boolean; issue: Issue, - onFail: Error => void, onFilter?: (property: string, issue: Issue) => void, togglePopup: (string, boolean | void) => void |}; @@ -89,7 +88,6 @@ export default function IssueTitleBar(props /*: Props */) { creationDate={issue.creationDate} isOpen={props.currentPopup === 'changelog'} issue={issue} - onFail={props.onFail} togglePopup={props.togglePopup} /> </li> @@ -125,7 +123,6 @@ export default function IssueTitleBar(props /*: Props */) { <SimilarIssuesFilter isOpen={props.currentPopup === 'similarIssues'} issue={issue} - onFail={props.onFail} onFilter={props.onFilter} togglePopup={props.togglePopup} /> diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTransition.js b/server/sonar-web/src/main/js/components/issue/components/IssueTransition.js index 52b17fba604..f57008c6691 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueTransition.js +++ b/server/sonar-web/src/main/js/components/issue/components/IssueTransition.js @@ -34,7 +34,6 @@ type Props = { isOpen: boolean, issue: Issue, onChange: Issue => void, - onFail: Error => void, togglePopup: (string, boolean | void) => void }; */ @@ -45,7 +44,6 @@ export default class IssueTransition extends React.PureComponent { setTransition = (transition /*: string */) => { updateIssue( this.props.onChange, - this.props.onFail, setIssueTransition({ issue: this.props.issue.key, transition }) ); this.toggleSetTransition(); diff --git a/server/sonar-web/src/main/js/components/issue/components/SimilarIssuesFilter.js b/server/sonar-web/src/main/js/components/issue/components/SimilarIssuesFilter.js index 7126df24225..a47d9fad24e 100644 --- a/server/sonar-web/src/main/js/components/issue/components/SimilarIssuesFilter.js +++ b/server/sonar-web/src/main/js/components/issue/components/SimilarIssuesFilter.js @@ -32,7 +32,6 @@ type Props = {| isOpen: boolean, issue: Issue, togglePopup: (string, boolean | void) => void, - onFail: Error => void, onFilter: (property: string, issue: Issue) => void |}; */ diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueAssign-test.js b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueAssign-test.js index ad39643695e..b426640ed31 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueAssign-test.js +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueAssign-test.js @@ -35,7 +35,6 @@ it('should render without the action when the correct rights are missing', () => isOpen={false} issue={issue} onAssign={jest.fn()} - onFail={jest.fn()} togglePopup={jest.fn()} /> ); @@ -49,7 +48,6 @@ it('should render with the action', () => { isOpen={false} issue={issue} onAssign={jest.fn()} - onFail={jest.fn()} togglePopup={jest.fn()} /> ); @@ -64,7 +62,6 @@ it('should open the popup when the button is clicked', () => { isOpen={false} issue={issue} onAssign={jest.fn()} - onFail={jest.fn()} togglePopup={toggle} /> ); diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueChangelog-test.js b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueChangelog-test.js index 8e03fdef42a..fd81fcc3734 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueChangelog-test.js +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueChangelog-test.js @@ -34,7 +34,6 @@ it('should render correctly', () => { creationDate="2017-03-01T09:36:01+0100" isOpen={false} issue={issue} - onFail={jest.fn()} togglePopup={jest.fn()} /> ); @@ -48,7 +47,6 @@ it('should open the popup when the button is clicked', () => { creationDate="2017-03-01T09:36:01+0100" isOpen={false} issue={issue} - onFail={jest.fn()} togglePopup={toggle} /> ); diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueCommentAction-test.js b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueCommentAction-test.js index 2114f366226..5a6317e63e0 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueCommentAction-test.js +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueCommentAction-test.js @@ -27,7 +27,6 @@ it('should render correctly', () => { <IssueCommentAction currentPopup={null} issueKey="issue-key" - onFail={jest.fn()} onIssueChange={jest.fn()} toggleComment={jest.fn()} /> @@ -41,7 +40,6 @@ it('should open the popup when the button is clicked', () => { <IssueCommentAction currentPopup={null} issueKey="issue-key" - onFail={jest.fn()} onIssueChange={jest.fn()} toggleComment={toggle} /> diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.js b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.js index 81d9a512a45..cf7efb121cd 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.js +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.js @@ -37,7 +37,6 @@ it('should render without the action when the correct rights are missing', () => transitions: [], status: 'CLOSED' }} - onFail={jest.fn()} onIssueChange={jest.fn()} togglePopup={jest.fn()} /> @@ -51,7 +50,6 @@ it('should render with the action', () => { canSetTags={true} isOpen={false} issue={issue} - onFail={jest.fn()} onIssueChange={jest.fn()} togglePopup={jest.fn()} /> @@ -66,7 +64,6 @@ it('should open the popup when the button is clicked', () => { canSetTags={true} isOpen={false} issue={issue} - onFail={jest.fn()} onIssueChange={jest.fn()} togglePopup={toggle} /> diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTitleBar-test.js b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTitleBar-test.js index 4a917cf1ead..78ae2b7b1ef 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTitleBar-test.js +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTitleBar-test.js @@ -52,7 +52,6 @@ it('should render the titlebar correctly', () => { branchLike={{ isMain: false, name: 'feature-1.0', type: 'SHORT' }} currentPopup={null} issue={issue} - onFail={jest.fn()} togglePopup={jest.fn()} /> ); @@ -61,13 +60,7 @@ it('should render the titlebar correctly', () => { it('should render the titlebar with the filter', () => { const element = shallow( - <IssueTitleBar - currentPopup={null} - issue={issue} - onFail={jest.fn()} - onFilter={jest.fn()} - togglePopup={jest.fn()} - /> + <IssueTitleBar currentPopup={null} issue={issue} onFilter={jest.fn()} togglePopup={jest.fn()} /> ); expect(element).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.js.snap b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.js.snap index d768c0c852d..3ac74928b8f 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.js.snap +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.js.snap @@ -26,7 +26,6 @@ exports[`should open the popup when the button is clicked 2`] = ` "assigneeName": "John Doe", } } - onFail={[MockFunction]} onSelect={[MockFunction]} /> } @@ -77,7 +76,6 @@ exports[`should render with the action 1`] = ` "assigneeName": "John Doe", } } - onFail={[MockFunction]} onSelect={[MockFunction]} /> } diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueChangelog-test.js.snap b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueChangelog-test.js.snap index 7ba9bfa806c..fad46a6b759 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueChangelog-test.js.snap +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueChangelog-test.js.snap @@ -25,7 +25,6 @@ exports[`should open the popup when the button is clicked 2`] = ` "key": "issuekey", } } - onFail={[MockFunction]} /> } > @@ -73,7 +72,6 @@ exports[`should render correctly 1`] = ` "key": "issuekey", } } - onFail={[MockFunction]} /> } > diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.js.snap b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.js.snap index b61379d35ab..9aed610d4ce 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.js.snap +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.js.snap @@ -48,7 +48,6 @@ exports[`should render the titlebar correctly 1`] = ` }, } } - onFail={[MockFunction]} togglePopup={[MockFunction]} /> </li> @@ -134,7 +133,6 @@ exports[`should render the titlebar with the filter 1`] = ` }, } } - onFail={[MockFunction]} togglePopup={[MockFunction]} /> </li> @@ -197,7 +195,6 @@ exports[`should render the titlebar with the filter 1`] = ` }, } } - onFail={[MockFunction]} onFilter={[MockFunction]} togglePopup={[MockFunction]} /> diff --git a/server/sonar-web/src/main/js/components/issue/popups/ChangelogPopup.js b/server/sonar-web/src/main/js/components/issue/popups/ChangelogPopup.js index a9ec681f27b..71c5d3b5b00 100644 --- a/server/sonar-web/src/main/js/components/issue/popups/ChangelogPopup.js +++ b/server/sonar-web/src/main/js/components/issue/popups/ChangelogPopup.js @@ -41,7 +41,6 @@ type Changelog = { /*:: type Props = { issue: Issue, - onFail: Error => void, popupPosition?: {} }; */ @@ -69,11 +68,14 @@ export default class ChangelogPopup extends React.PureComponent { } loadChangelog() { - getIssueChangelog(this.props.issue.key).then(changelogs => { - if (this.mounted) { - this.setState({ changelogs }); - } - }, this.props.onFail); + getIssueChangelog(this.props.issue.key).then( + changelogs => { + if (this.mounted) { + this.setState({ changelogs }); + } + }, + () => {} + ); } render() { diff --git a/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.js b/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.js index a1758698ec8..434bfa9e196 100644 --- a/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.js +++ b/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.js @@ -46,7 +46,6 @@ type User = { type Props = { currentUser: User, issue: Issue, - onFail: Error => void, onSelect: string => void, popupPosition?: {} }; @@ -91,11 +90,12 @@ class SetAssigneePopup extends React.PureComponent { organization: this.props.issue.projectOrganization, q: query, ps: LIST_SIZE - }).then(this.handleSearchResult, this.props.onFail); + }).then(this.handleSearchResult, () => {}); }; - searchUsers = (query /*: string */) => - searchUsers({ q: query, ps: LIST_SIZE }).then(this.handleSearchResult, this.props.onFail); + searchUsers = (query /*: string */) => { + searchUsers({ q: query, ps: LIST_SIZE }).then(this.handleSearchResult, () => {}); + }; handleSearchResult = (data /*: Object */) => { this.setState({ diff --git a/server/sonar-web/src/main/js/components/issue/popups/__tests__/ChangelogPopup-test.js b/server/sonar-web/src/main/js/components/issue/popups/__tests__/ChangelogPopup-test.js index f08b7b05f60..fa67372738e 100644 --- a/server/sonar-web/src/main/js/components/issue/popups/__tests__/ChangelogPopup-test.js +++ b/server/sonar-web/src/main/js/components/issue/popups/__tests__/ChangelogPopup-test.js @@ -29,7 +29,6 @@ it('should render the changelog popup correctly', () => { author: 'john.david.dalton@gmail.com', creationDate: '2017-03-01T09:36:01+0100' }} - onFail={jest.fn()} /> ); element.setState({ diff --git a/server/sonar-web/src/main/js/components/measure/types.js b/server/sonar-web/src/main/js/components/measure/types.js index 623292e882e..a5a8c4ae473 100644 --- a/server/sonar-web/src/main/js/components/measure/types.js +++ b/server/sonar-web/src/main/js/components/measure/types.js @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // @flow -/*:: import type { Metric } from '../../store/metrics/actions'; */ +/*:: import type { Metric } from '../../app/flow-types'; */ /*:: type MeasureIntern = { value?: string, diff --git a/server/sonar-web/src/main/js/components/shared/Organization.tsx b/server/sonar-web/src/main/js/components/shared/Organization.tsx index 023a8ba563c..2dcfdaeb7d6 100644 --- a/server/sonar-web/src/main/js/components/shared/Organization.tsx +++ b/server/sonar-web/src/main/js/components/shared/Organization.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import { connect } from 'react-redux'; -import { getOrganizationByKey, areThereCustomOrganizations } from '../../store/rootReducer'; +import { getOrganizationByKey, areThereCustomOrganizations, Store } from '../../store/rootReducer'; import OrganizationLink from '../ui/OrganizationLink'; interface OwnProps { @@ -30,7 +30,7 @@ interface Props { link?: boolean; linkClassName?: string; organization: { key: string; name: string } | null; - shouldBeDisplayed: boolean; + shouldBeDisplayed?: boolean; } function Organization(props: Props) { @@ -54,11 +54,11 @@ function Organization(props: Props) { ); } -const mapStateToProps = (state: any, ownProps: OwnProps) => ({ +const mapStateToProps = (state: Store, ownProps: OwnProps) => ({ organization: getOrganizationByKey(state, ownProps.organizationKey), shouldBeDisplayed: areThereCustomOrganizations(state) }); -export default connect<any, any, any>(mapStateToProps)(Organization); +export default connect(mapStateToProps)(Organization); export const UnconnectedOrganization = Organization; diff --git a/server/sonar-web/src/main/js/components/ui/Avatar.tsx b/server/sonar-web/src/main/js/components/ui/Avatar.tsx index 7657c13419c..ad31cabb65d 100644 --- a/server/sonar-web/src/main/js/components/ui/Avatar.tsx +++ b/server/sonar-web/src/main/js/components/ui/Avatar.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import * as classNames from 'classnames'; import GenericAvatar from './GenericAvatar'; -import { getGlobalSettingValue } from '../../store/rootReducer'; +import { getGlobalSettingValue, Store } from '../../store/rootReducer'; interface Props { className?: string; @@ -55,7 +55,7 @@ function Avatar(props: Props) { ); } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: Store) => ({ enableGravatar: (getGlobalSettingValue(state, 'sonar.lf.enableGravatar') || {}).value === 'true', gravatarServerUrl: (getGlobalSettingValue(state, 'sonar.lf.gravatarServerUrl') || {}).value }); diff --git a/server/sonar-web/src/main/js/store/__tests__/__snapshots__/organizations-test.ts.snap b/server/sonar-web/src/main/js/store/__tests__/__snapshots__/organizations-test.ts.snap new file mode 100644 index 00000000000..bc2ba11d2bc --- /dev/null +++ b/server/sonar-web/src/main/js/store/__tests__/__snapshots__/organizations-test.ts.snap @@ -0,0 +1,97 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Reducer should create organization 1`] = ` +Object { + "byKey": Object { + "foo": Object { + "isAdmin": true, + "key": "foo", + "name": "foo", + }, + }, + "my": Array [ + "foo", + ], +} +`; + +exports[`Reducer should delete organization 1`] = ` +Object { + "byKey": Object {}, + "my": Array [], +} +`; + +exports[`Reducer should have initial state 1`] = ` +Object { + "byKey": Object {}, + "my": Array [], +} +`; + +exports[`Reducer should receive my organizations 1`] = ` +Object { + "byKey": Object { + "bar": Object { + "key": "bar", + "name": "Bar", + }, + "foo": Object { + "key": "foo", + "name": "Foo", + }, + }, + "my": Array [ + "foo", + "bar", + ], +} +`; + +exports[`Reducer should receive organizations 1`] = ` +Object { + "byKey": Object { + "bar": Object { + "key": "bar", + "name": "Bar", + }, + "foo": Object { + "key": "foo", + "name": "Foo", + }, + }, + "my": Array [], +} +`; + +exports[`Reducer should receive organizations 2`] = ` +Object { + "byKey": Object { + "bar": Object { + "key": "bar", + "name": "Bar", + }, + "foo": Object { + "key": "foo", + "name": "Qwe", + }, + }, + "my": Array [], +} +`; + +exports[`Reducer should update organization 1`] = ` +Object { + "byKey": Object { + "foo": Object { + "description": "description", + "isAdmin": true, + "key": "foo", + "name": "bar", + }, + }, + "my": Array [ + "foo", + ], +} +`; diff --git a/server/sonar-web/src/main/js/store/__tests__/organizations-test.ts b/server/sonar-web/src/main/js/store/__tests__/organizations-test.ts new file mode 100644 index 00000000000..41233545f96 --- /dev/null +++ b/server/sonar-web/src/main/js/store/__tests__/organizations-test.ts @@ -0,0 +1,103 @@ +/* + * 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 reducer, { + getOrganizationByKey, + areThereCustomOrganizations, + getMyOrganizations, + State, + receiveOrganizations, + receiveMyOrganizations, + createOrganization, + updateOrganization, + deleteOrganization +} from '../organizations'; + +const state0: State = { byKey: {}, my: [] }; + +describe('Reducer', () => { + it('should have initial state', () => { + // @ts-ignore `undefined` is passed when the redux store is created, + // however should not be allowed by typings + expect(reducer(undefined, {})).toMatchSnapshot(); + }); + + it('should receive organizations', () => { + const state1 = reducer( + state0, + receiveOrganizations([{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }]) + ); + expect(state1).toMatchSnapshot(); + + const state2 = reducer(state1, receiveOrganizations([{ key: 'foo', name: 'Qwe' }])); + expect(state2).toMatchSnapshot(); + }); + + it('should receive my organizations', () => { + const state1 = reducer( + state0, + receiveMyOrganizations([{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }]) + ); + expect(state1).toMatchSnapshot(); + }); + + it('should create organization', () => { + const state1 = reducer(state0, createOrganization({ key: 'foo', name: 'foo' })); + expect(state1).toMatchSnapshot(); + }); + + it('should update organization', () => { + const state1 = reducer(state0, createOrganization({ key: 'foo', name: 'foo' })); + const state2 = reducer( + state1, + updateOrganization('foo', { name: 'bar', description: 'description' }) + ); + expect(state2).toMatchSnapshot(); + }); + + it('should delete organization', () => { + const state1 = reducer(state0, createOrganization({ key: 'foo', name: 'foo' })); + const state2 = reducer(state1, deleteOrganization('foo')); + expect(state2).toMatchSnapshot(); + }); +}); + +describe('Selectors', () => { + it('getOrganizationByKey', () => { + const foo = { key: 'foo', name: 'Foo' }; + const state = { ...state0, byKey: { foo } }; + expect(getOrganizationByKey(state, 'foo')).toBe(foo); + expect(getOrganizationByKey(state, 'bar')).toBeFalsy(); + }); + + it('getMyOrganizations', () => { + expect(getMyOrganizations(state0)).toEqual([]); + + const foo = { key: 'foo', name: 'Foo' }; + expect(getMyOrganizations({ ...state0, byKey: { foo }, my: ['foo'] })).toEqual([foo]); + }); + + it('areThereCustomOrganizations', () => { + const foo = { key: 'foo', name: 'Foo' }; + const bar = { key: 'bar', name: 'Bar' }; + expect(areThereCustomOrganizations({ ...state0, byKey: {} })).toBe(false); + expect(areThereCustomOrganizations({ ...state0, byKey: { foo } })).toBe(false); + expect(areThereCustomOrganizations({ ...state0, byKey: { foo, bar } })).toBe(true); + }); +}); diff --git a/server/sonar-web/src/main/js/store/appState/duck.ts b/server/sonar-web/src/main/js/store/appState.ts index 79ada585879..19a5e546944 100644 --- a/server/sonar-web/src/main/js/store/appState/duck.ts +++ b/server/sonar-web/src/main/js/store/appState.ts @@ -17,44 +17,36 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { Extension, AppState } from '../../app/types'; +import { ActionType } from './utils/actions'; +import { Extension, AppState } from '../app/types'; +import { EditionKey } from '../apps/marketplace/utils'; -interface SetAppStateAction { - type: 'SET_APP_STATE'; - appState: AppState; -} - -interface SetAdminPagesAction { - type: 'SET_ADMIN_PAGES'; - adminPages: Extension[]; -} - -interface RequireAuthorizationAction { - type: 'REQUIRE_AUTHORIZATION'; -} - -export type Action = SetAppStateAction | SetAdminPagesAction | RequireAuthorizationAction; +type Action = + | ActionType<typeof setAppState, 'SET_APP_STATE'> + | ActionType<typeof setAdminPages, 'SET_ADMIN_PAGES'> + | ActionType<typeof requireAuthorization, 'REQUIRE_AUTHORIZATION'>; -export function setAppState(appState: AppState): SetAppStateAction { - return { - type: 'SET_APP_STATE', - appState - }; +export function setAppState(appState: AppState) { + return { type: 'SET_APP_STATE', appState }; } -export function setAdminPages(adminPages: Extension[]): SetAdminPagesAction { +export function setAdminPages(adminPages: Extension[]) { return { type: 'SET_ADMIN_PAGES', adminPages }; } -export function requireAuthorization(): RequireAuthorizationAction { +export function requireAuthorization() { return { type: 'REQUIRE_AUTHORIZATION' }; } const defaultValue: AppState = { authenticationError: false, authorizationError: false, + defaultOrganization: '', + edition: EditionKey.community, organizationsEnabled: false, - qualifiers: [] + productionDatabase: true, + qualifiers: [], + version: '' }; export default function(state: AppState = defaultValue, action: Action): AppState { diff --git a/server/sonar-web/src/main/js/store/globalMessages.ts b/server/sonar-web/src/main/js/store/globalMessages.ts new file mode 100644 index 00000000000..370ecb1bcc8 --- /dev/null +++ b/server/sonar-web/src/main/js/store/globalMessages.ts @@ -0,0 +1,102 @@ +/* + * 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 { uniqueId } from 'lodash'; +import { Dispatch } from 'redux'; +import { requireAuthorization } from './appState'; +import { Store } from './rootReducer'; +import { ActionType } from './utils/actions'; + +enum MessageLevel { + Error = 'ERROR', + Success = 'SUCCESS' +} + +interface Message { + id: string; + message: string; + level: MessageLevel; +} + +function addGlobalMessageActionCreator(id: string, message: string, level: MessageLevel) { + return { type: 'ADD_GLOBAL_MESSAGE', message, level, id }; +} + +export function closeGlobalMessage(id: string) { + return { type: 'CLOSE_GLOBAL_MESSAGE', id }; +} + +export function closeAllGlobalMessages(id: string) { + return { type: 'CLOSE_ALL_GLOBAL_MESSAGES', id }; +} + +type Action = + | ActionType<typeof addGlobalMessageActionCreator, 'ADD_GLOBAL_MESSAGE'> + | ActionType<typeof closeGlobalMessage, 'CLOSE_GLOBAL_MESSAGE'> + | ActionType<typeof closeAllGlobalMessages, 'CLOSE_ALL_GLOBAL_MESSAGES'> + | ActionType<typeof requireAuthorization, 'REQUIRE_AUTHORIZATION'>; + +function addGlobalMessage(message: string, level: MessageLevel) { + return (dispatch: Dispatch<Store>) => { + const id = uniqueId('global-message-'); + dispatch(addGlobalMessageActionCreator(id, message, level)); + setTimeout(() => dispatch(closeGlobalMessage(id)), 5000); + }; +} + +export function addGlobalErrorMessage(message: string) { + return addGlobalMessage(message, MessageLevel.Error); +} + +export function addGlobalSuccessMessage(message: string) { + return addGlobalMessage(message, MessageLevel.Success); +} + +export type State = Message[]; + +export default function(state: State = [], action: Action): State { + switch (action.type) { + case 'ADD_GLOBAL_MESSAGE': + return [{ id: action.id, message: action.message, level: action.level }]; + + case 'REQUIRE_AUTHORIZATION': + // FIXME l10n + return [ + { + id: uniqueId('global-message-'), + message: + 'You are not authorized to access this page. ' + + 'Please log in with more privileges and try again.', + level: MessageLevel.Error + } + ]; + + case 'CLOSE_GLOBAL_MESSAGE': + return state.filter(message => message.id !== action.id); + + case 'CLOSE_ALL_GLOBAL_MESSAGES': + return []; + default: + return state; + } +} + +export function getGlobalMessages(state: State) { + return state; +} diff --git a/server/sonar-web/src/main/js/store/globalMessages/duck.js b/server/sonar-web/src/main/js/store/globalMessages/duck.js deleted file mode 100644 index 81c4cba0ff6..00000000000 --- a/server/sonar-web/src/main/js/store/globalMessages/duck.js +++ /dev/null @@ -1,131 +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 { uniqueId } from 'lodash'; - -/*:: -type Level = 'ERROR' | 'SUCCESS'; -*/ - -/*:: -type Message = { - id: string, - message: string, - level: Level -}; -*/ - -/*:: -export type State = Array<Message>; -*/ - -/*:: -type Action = Object; -*/ - -const ERROR = 'ERROR'; -const SUCCESS = 'SUCCESS'; - -/* Actions */ -const ADD_GLOBAL_MESSAGE = 'ADD_GLOBAL_MESSAGE'; -const CLOSE_GLOBAL_MESSAGE = 'CLOSE_GLOBAL_MESSAGE'; -const CLOSE_ALL_GLOBAL_MESSAGES = 'CLOSE_ALL_GLOBAL_MESSAGES'; - -function addGlobalMessageActionCreator( - id /*: string */, - message /*: string */, - level /*: Level */ -) { - return { - type: ADD_GLOBAL_MESSAGE, - message, - level, - id - }; -} - -export function closeGlobalMessage(id /*: string */) { - return { - type: CLOSE_GLOBAL_MESSAGE, - id - }; -} - -export function closeAllGlobalMessages(id /*: string */) { - return { - type: CLOSE_ALL_GLOBAL_MESSAGES, - id - }; -} - -function addGlobalMessage(message /*: string */, level /*: Level */) { - return function(dispatch /*: Function */) { - const id = uniqueId('global-message-'); - dispatch(addGlobalMessageActionCreator(id, message, level)); - setTimeout(() => dispatch(closeGlobalMessage(id)), 5000); - }; -} - -export function addGlobalErrorMessage(message /*: string */) { - return addGlobalMessage(message, ERROR); -} - -export function addGlobalSuccessMessage(message /*: string */) { - return addGlobalMessage(message, SUCCESS); -} - -/* Reducer */ -export default function(state /*: State */ = [], action /*: Action */ = {}) { - switch (action.type) { - case ADD_GLOBAL_MESSAGE: - return [ - { - id: action.id, - message: action.message, - level: action.level - } - ]; - - case 'REQUIRE_AUTHORIZATION': - // FIXME l10n - return [ - { - id: uniqueId('global-message-'), - message: - 'You are not authorized to access this page. ' + - 'Please log in with more privileges and try again.', - level: ERROR - } - ]; - - case CLOSE_GLOBAL_MESSAGE: - return state.filter(message => message.id !== action.id); - - case CLOSE_ALL_GLOBAL_MESSAGES: - return []; - default: - return state; - } -} - -/* Selectors */ -export function getGlobalMessages(state /*: State */) { - return state; -} diff --git a/server/sonar-web/src/main/js/store/languages/reducer.ts b/server/sonar-web/src/main/js/store/languages.ts index 50caf69c59b..2cc95fe3006 100644 --- a/server/sonar-web/src/main/js/store/languages/reducer.ts +++ b/server/sonar-web/src/main/js/store/languages.ts @@ -18,22 +18,30 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { keyBy } from 'lodash'; -import { RECEIVE_LANGUAGES } from './actions'; +import { ActionType } from './utils/actions'; + +export function receiveLanguages(languages: Array<{ key: string; name: string }>) { + return { type: 'RECEIVE_LANGUAGES', languages }; +} + +type Action = ActionType<typeof receiveLanguages, 'RECEIVE_LANGUAGES'>; export interface Languages { [key: string]: { key: string; name: string }; } -const reducer = (state: Languages = {}, action: any = {}) => { - if (action.type === RECEIVE_LANGUAGES) { +export default function(state: Languages = {}, action: Action): Languages { + if (action.type === 'RECEIVE_LANGUAGES') { return keyBy(action.languages, 'key'); } return state; -}; - -export default reducer; +} -export const getLanguages = (state: Languages) => state; +export function getLanguages(state: Languages) { + return state; +} -export const getLanguageByKey = (state: Languages, key: string) => state[key]; +export function getLanguageByKey(state: Languages, key: string) { + return state[key]; +} diff --git a/server/sonar-web/src/main/js/store/metrics/reducer.js b/server/sonar-web/src/main/js/store/metrics.ts index d2d5284cc3a..85098902b21 100644 --- a/server/sonar-web/src/main/js/store/metrics/reducer.js +++ b/server/sonar-web/src/main/js/store/metrics.ts @@ -17,27 +17,28 @@ * 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 { combineReducers } from 'redux'; import { keyBy } from 'lodash'; -import { RECEIVE_METRICS } from './actions'; -/*:: import type { Metric } from './actions'; */ +import { combineReducers } from 'redux'; +import { ActionType } from './utils/actions'; +import { Metric } from '../app/types'; + +export function receiveMetrics(metrics: Metric[]) { + return { type: 'RECEIVE_METRICS', metrics }; +} -/*:: -type StateByKey = { [string]: Metric }; -type StateKeys = Array<string>; -type State = { byKey: StateByKey, keys: StateKeys }; -*/ +type Action = ActionType<typeof receiveMetrics, 'RECEIVE_METRICS'>; -const byKey = (state /*: StateByKey */ = {}, action = {}) => { - if (action.type === RECEIVE_METRICS) { +export type State = { byKey: { [key: string]: Metric }; keys: string[] }; + +const byKey = (state: State['byKey'] = {}, action: Action) => { + if (action.type === 'RECEIVE_METRICS') { return keyBy(action.metrics, 'key'); } return state; }; -const keys = (state /*: StateKeys */ = [], action = {}) => { - if (action.type === RECEIVE_METRICS) { +const keys = (state: State['keys'] = [], action: Action) => { + if (action.type === 'RECEIVE_METRICS') { return action.metrics.map(f => f.key); } @@ -46,5 +47,10 @@ const keys = (state /*: StateKeys */ = [], action = {}) => { export default combineReducers({ byKey, keys }); -export const getMetrics = (state /*: State */) => state.byKey; -export const getMetricsKey = (state /*: State */) => state.keys; +export function getMetrics(state: State) { + return state.byKey; +} + +export function getMetricsKey(state: State) { + return state.keys; +} diff --git a/server/sonar-web/src/main/js/store/organizations.ts b/server/sonar-web/src/main/js/store/organizations.ts new file mode 100644 index 00000000000..6b1dfdcc28c --- /dev/null +++ b/server/sonar-web/src/main/js/store/organizations.ts @@ -0,0 +1,116 @@ +/* + * 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 { combineReducers } from 'redux'; +import { omit, uniq, without } from 'lodash'; +import { ActionType } from './utils/actions'; +import { Organization, OrganizationBase } from '../app/types'; + +type ReceiveOrganizationsAction = + | ActionType<typeof receiveOrganizations, 'RECEIVE_ORGANIZATIONS'> + | ActionType<typeof receiveMyOrganizations, 'RECEIVE_MY_ORGANIZATIONS'>; + +type Action = + | ReceiveOrganizationsAction + | ActionType<typeof createOrganization, 'CREATE_ORGANIZATION'> + | ActionType<typeof updateOrganization, 'UPDATE_ORGANIZATION'> + | ActionType<typeof deleteOrganization, 'DELETE_ORGANIZATION'>; + +export interface State { + byKey: { [key: string]: Organization }; + my: string[]; +} + +export function receiveOrganizations(organizations: Organization[]) { + return { type: 'RECEIVE_ORGANIZATIONS', organizations }; +} + +export function receiveMyOrganizations(organizations: Organization[]) { + return { type: 'RECEIVE_MY_ORGANIZATIONS', organizations }; +} + +export function createOrganization(organization: Organization) { + return { type: 'CREATE_ORGANIZATION', organization }; +} + +export function updateOrganization(key: string, changes: OrganizationBase) { + return { type: 'UPDATE_ORGANIZATION', key, changes }; +} + +export function deleteOrganization(key: string) { + return { type: 'DELETE_ORGANIZATION', key }; +} + +function onReceiveOrganizations(state: State['byKey'], action: ReceiveOrganizationsAction) { + const nextState = { ...state }; + action.organizations.forEach(organization => { + nextState[organization.key] = { ...state[organization.key], ...organization }; + }); + return nextState; +} + +function byKey(state: State['byKey'] = {}, action: Action): State['byKey'] { + switch (action.type) { + case 'RECEIVE_ORGANIZATIONS': + case 'RECEIVE_MY_ORGANIZATIONS': + return onReceiveOrganizations(state, action); + case 'CREATE_ORGANIZATION': + return { ...state, [action.organization.key]: { ...action.organization, isAdmin: true } }; + case 'UPDATE_ORGANIZATION': + return { + ...state, + [action.key]: { + ...state[action.key], + key: action.key, + ...action.changes + } + }; + case 'DELETE_ORGANIZATION': + return omit(state, action.key); + default: + return state; + } +} + +function my(state: State['my'] = [], action: Action): State['my'] { + switch (action.type) { + case 'RECEIVE_MY_ORGANIZATIONS': + return uniq([...state, ...action.organizations.map(o => o.key)]); + case 'CREATE_ORGANIZATION': + return uniq([...state, action.organization.key]); + case 'DELETE_ORGANIZATION': + return without(state, action.key); + default: + return state; + } +} + +export default combineReducers({ byKey, my }); + +export function getOrganizationByKey(state: State, key: string) { + return state.byKey[key]; +} + +export function getMyOrganizations(state: State) { + return state.my.map(key => getOrganizationByKey(state, key)); +} + +export function areThereCustomOrganizations(state: State) { + return Object.keys(state.byKey).length > 1; +} diff --git a/server/sonar-web/src/main/js/store/organizations/__tests__/__snapshots__/duck-test.ts.snap b/server/sonar-web/src/main/js/store/organizations/__tests__/__snapshots__/duck-test.ts.snap deleted file mode 100644 index c5ad9b73625..00000000000 --- a/server/sonar-web/src/main/js/store/organizations/__tests__/__snapshots__/duck-test.ts.snap +++ /dev/null @@ -1,43 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Reducer should have initial state 1`] = ` -Object { - "byKey": Object {}, - "groups": Object {}, - "my": Array [], -} -`; - -exports[`Reducer should receive organizations 1`] = ` -Object { - "byKey": Object { - "bar": Object { - "key": "bar", - "name": "Bar", - }, - "foo": Object { - "key": "foo", - "name": "Foo", - }, - }, - "groups": Object {}, - "my": Array [], -} -`; - -exports[`Reducer should receive organizations 2`] = ` -Object { - "byKey": Object { - "bar": Object { - "key": "bar", - "name": "Bar", - }, - "foo": Object { - "key": "foo", - "name": "Qwe", - }, - }, - "groups": Object {}, - "my": Array [], -} -`; diff --git a/server/sonar-web/src/main/js/store/organizations/__tests__/duck-test.ts b/server/sonar-web/src/main/js/store/organizations/__tests__/duck-test.ts deleted file mode 100644 index e9321e29f90..00000000000 --- a/server/sonar-web/src/main/js/store/organizations/__tests__/duck-test.ts +++ /dev/null @@ -1,61 +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 organizations, { getOrganizationByKey, areThereCustomOrganizations } from '../duck'; - -const state0 = { byKey: {}, my: [], groups: {} }; - -describe('Reducer', () => { - it('should have initial state', () => { - expect((organizations as any)(undefined, {})).toMatchSnapshot(); - }); - - it('should receive organizations', () => { - const action1 = { - type: 'RECEIVE_ORGANIZATIONS', - organizations: [{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }] - }; - const state1 = organizations(state0, action1); - expect(state1).toMatchSnapshot(); - - const action2 = { - type: 'RECEIVE_ORGANIZATIONS', - organizations: [{ key: 'foo', name: 'Qwe' }] - }; - const state2 = organizations(state1, action2); - expect(state2).toMatchSnapshot(); - }); -}); - -describe('Selectors', () => { - it('getOrganizationByKey', () => { - const foo = { key: 'foo', name: 'Foo' }; - const state = { ...state0, byKey: { foo } }; - expect(getOrganizationByKey(state, 'foo')).toBe(foo); - expect(getOrganizationByKey(state, 'bar')).toBeFalsy(); - }); - - it('areThereCustomOrganizations', () => { - const foo = { key: 'foo', name: 'Foo' }; - const bar = { key: 'bar', name: 'Bar' }; - expect(areThereCustomOrganizations({ ...state0, byKey: {} })).toBe(false); - expect(areThereCustomOrganizations({ ...state0, byKey: { foo } })).toBe(false); - expect(areThereCustomOrganizations({ ...state0, byKey: { foo, bar } })).toBe(true); - }); -}); diff --git a/server/sonar-web/src/main/js/store/organizations/duck.ts b/server/sonar-web/src/main/js/store/organizations/duck.ts deleted file mode 100644 index 5f01ac95261..00000000000 --- a/server/sonar-web/src/main/js/store/organizations/duck.ts +++ /dev/null @@ -1,199 +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 { combineReducers } from 'redux'; -import { omit, uniq, without } from 'lodash'; -import { Group, Organization, OrganizationBase } from '../../app/types'; - -interface ReceiveOrganizationsAction { - type: 'RECEIVE_ORGANIZATIONS'; - organizations: Organization[]; -} - -interface ReceiveMyOrganizationsAction { - type: 'RECEIVE_MY_ORGANIZATIONS'; - organizations: Organization[]; -} - -interface ReceiveOrganizationGroups { - type: 'RECEIVE_ORGANIZATION_GROUPS'; - key: string; - groups: Group[]; -} - -interface CreateOrganizationAction { - type: 'CREATE_ORGANIZATION'; - organization: Organization; -} - -interface UpdateOrganizationAction { - type: 'UPDATE_ORGANIZATION'; - key: string; - changes: {}; -} - -interface DeleteOrganizationAction { - type: 'DELETE_ORGANIZATION'; - key: string; -} - -type Action = - | ReceiveOrganizationsAction - | ReceiveMyOrganizationsAction - | ReceiveOrganizationGroups - | CreateOrganizationAction - | UpdateOrganizationAction - | DeleteOrganizationAction; - -interface ByKeyState { - [key: string]: Organization; -} - -interface GroupsState { - [key: string]: Group[]; -} - -type MyState = string[]; - -interface State { - byKey: ByKeyState; - my: MyState; - groups: GroupsState; -} - -export function receiveOrganizations(organizations: Organization[]): ReceiveOrganizationsAction { - return { - type: 'RECEIVE_ORGANIZATIONS', - organizations - }; -} - -export function receiveMyOrganizations( - organizations: Organization[] -): ReceiveMyOrganizationsAction { - return { - type: 'RECEIVE_MY_ORGANIZATIONS', - organizations - }; -} - -export function receiveOrganizationGroups(key: string, groups: Group[]): ReceiveOrganizationGroups { - return { - type: 'RECEIVE_ORGANIZATION_GROUPS', - key, - groups - }; -} - -export function createOrganization(organization: Organization): CreateOrganizationAction { - return { - type: 'CREATE_ORGANIZATION', - organization - }; -} - -export function updateOrganization( - key: string, - changes: OrganizationBase -): UpdateOrganizationAction { - return { - type: 'UPDATE_ORGANIZATION', - key, - changes - }; -} - -export function deleteOrganization(key: string): DeleteOrganizationAction { - return { - type: 'DELETE_ORGANIZATION', - key - }; -} - -function onReceiveOrganizations( - state: ByKeyState, - action: ReceiveOrganizationsAction | ReceiveMyOrganizationsAction -): ByKeyState { - const nextState = { ...state }; - action.organizations.forEach(organization => { - nextState[organization.key] = { ...state[organization.key], ...organization }; - }); - return nextState; -} - -function byKey(state: ByKeyState = {}, action: Action) { - switch (action.type) { - case 'RECEIVE_ORGANIZATIONS': - case 'RECEIVE_MY_ORGANIZATIONS': - return onReceiveOrganizations(state, action); - case 'CREATE_ORGANIZATION': - return { ...state, [action.organization.key]: { ...action.organization, isAdmin: true } }; - case 'UPDATE_ORGANIZATION': - return { - ...state, - [action.key]: { - ...state[action.key], - key: action.key, - ...action.changes - } - }; - case 'DELETE_ORGANIZATION': - return omit(state, action.key); - default: - return state; - } -} - -function my(state: MyState = [], action: Action) { - switch (action.type) { - case 'RECEIVE_MY_ORGANIZATIONS': - return uniq([...state, ...action.organizations.map(o => o.key)]); - case 'CREATE_ORGANIZATION': - return uniq([...state, action.organization.key]); - case 'DELETE_ORGANIZATION': - return without(state, action.key); - default: - return state; - } -} - -function groups(state: GroupsState = {}, action: Action) { - if (action.type === 'RECEIVE_ORGANIZATION_GROUPS') { - return { ...state, [action.key]: action.groups }; - } - return state; -} - -export default combineReducers<State>({ byKey, my, groups }); - -export function getOrganizationByKey(state: State, key: string): Organization | undefined { - return state.byKey[key]; -} - -export function getOrganizationGroupsByKey(state: State, key: string): Group[] { - return state.groups[key] || []; -} - -export function getMyOrganizations(state: State): Organization[] { - return state.my.map(key => getOrganizationByKey(state, key) as Organization); -} - -export function areThereCustomOrganizations(state: State): boolean { - return Object.keys(state.byKey).length > 1; -} diff --git a/server/sonar-web/src/main/js/store/rootActions.js b/server/sonar-web/src/main/js/store/rootActions.js deleted file mode 100644 index c49e3921c6c..00000000000 --- a/server/sonar-web/src/main/js/store/rootActions.js +++ /dev/null @@ -1,67 +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 { setAppState } from './appState/duck'; -import { receiveOrganizations } from './organizations/duck'; -import { receiveLanguages } from './languages/actions'; -import { receiveMetrics } from './metrics/actions'; -import { addGlobalErrorMessage } from './globalMessages/duck'; -import { getLanguages } from '../api/languages'; -import { getGlobalNavigation } from '../api/nav'; -import * as auth from '../api/auth'; -import { getOrganizations } from '../api/organizations'; -import { getAllMetrics } from '../api/metrics'; -import { parseError } from '../helpers/request'; - -export const onFail = dispatch => error => - parseError(error).then(message => dispatch(addGlobalErrorMessage(message))); - -export const fetchLanguages = () => dispatch => - getLanguages().then(languages => dispatch(receiveLanguages(languages)), onFail(dispatch)); - -export const fetchMetrics = () => dispatch => - getAllMetrics().then(metrics => dispatch(receiveMetrics(metrics)), onFail(dispatch)); - -export const fetchOrganizations = (organizations /*: Array<string> | void */) => dispatch => - getOrganizations({ organizations: organizations && organizations.join() }).then( - r => dispatch(receiveOrganizations(r.organizations)), - onFail(dispatch) - ); - -export const doLogin = (login, password) => dispatch => - auth.login(login, password).then( - () => { - /* everything is fine */ - }, - () => { - dispatch(addGlobalErrorMessage('Authentication failed')); - return Promise.reject(); - } - ); - -export const doLogout = () => dispatch => - auth.logout().then( - () => { - /* everything is fine */ - }, - () => { - dispatch(addGlobalErrorMessage('Logout failed')); - return Promise.reject(); - } - ); diff --git a/server/sonar-web/src/main/js/store/rootActions.ts b/server/sonar-web/src/main/js/store/rootActions.ts new file mode 100644 index 00000000000..52ab8e776b6 --- /dev/null +++ b/server/sonar-web/src/main/js/store/rootActions.ts @@ -0,0 +1,76 @@ +/* + * 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 { Dispatch } from 'redux'; +import { addGlobalErrorMessage } from './globalMessages'; +import { receiveLanguages } from './languages'; +import { receiveMetrics } from './metrics'; +import { receiveOrganizations } from './organizations'; +import { Store } from './rootReducer'; +import * as auth from '../api/auth'; +import { getLanguages } from '../api/languages'; +import { getAllMetrics } from '../api/metrics'; +import { getOrganizations } from '../api/organizations'; + +export function fetchLanguages() { + return (dispatch: Dispatch<Store>) => { + getLanguages().then(languages => dispatch(receiveLanguages(languages)), () => {}); + }; +} + +export function fetchMetrics() { + return (dispatch: Dispatch<Store>) => { + getAllMetrics().then(metrics => dispatch(receiveMetrics(metrics)), () => {}); + }; +} + +export function fetchOrganizations(organizations: string[]) { + return (dispatch: Dispatch<Store>) => { + getOrganizations({ organizations: organizations && organizations.join() }).then( + r => dispatch(receiveOrganizations(r.organizations)), + () => {} + ); + }; +} + +export function doLogin(login: string, password: string) { + return (dispatch: Dispatch<Store>) => + auth.login(login, password).then( + () => { + /* everything is fine */ + }, + () => { + dispatch(addGlobalErrorMessage('Authentication failed')); + return Promise.reject(); + } + ); +} + +export function doLogout() { + return (dispatch: Dispatch<Store>) => + auth.logout().then( + () => { + /* everything is fine */ + }, + () => { + dispatch(addGlobalErrorMessage('Logout failed')); + return Promise.reject(); + } + ); +} diff --git a/server/sonar-web/src/main/js/store/rootReducer.js b/server/sonar-web/src/main/js/store/rootReducer.js deleted file mode 100644 index 16d038d1e89..00000000000 --- a/server/sonar-web/src/main/js/store/rootReducer.js +++ /dev/null @@ -1,114 +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 { combineReducers } from 'redux'; -import appState from './appState/duck'; -import users, * as fromUsers from './users/reducer'; -import languages, * as fromLanguages from './languages/reducer'; -import metrics, * as fromMetrics from './metrics/reducer'; -import organizations, * as fromOrganizations from './organizations/duck'; -import globalMessages, * as fromGlobalMessages from './globalMessages/duck'; -import permissionsApp, * as fromPermissionsApp from '../apps/permissions/shared/store/rootReducer'; -import projectAdminApp, * as fromProjectAdminApp from '../apps/project-admin/store/rootReducer'; -import settingsApp, * as fromSettingsApp from '../apps/settings/store/rootReducer'; - -export default combineReducers({ - appState, - globalMessages, - languages, - metrics, - organizations, - users, - - // apps - permissionsApp, - projectAdminApp, - settingsApp -}); - -export const getAppState = state => state.appState; - -export const getGlobalMessages = state => - fromGlobalMessages.getGlobalMessages(state.globalMessages); - -export const getLanguages = state => fromLanguages.getLanguages(state.languages); - -export const getCurrentUser = state => fromUsers.getCurrentUser(state.users); - -export const getUsersByLogins = (state, logins) => fromUsers.getUsersByLogins(state.users, logins); - -export const getMetrics = state => fromMetrics.getMetrics(state.metrics); - -export const getMetricsKey = state => fromMetrics.getMetricsKey(state.metrics); - -export const getOrganizationByKey = (state, key) => - fromOrganizations.getOrganizationByKey(state.organizations, key); - -export const getOrganizationGroupsByKey = (state, key) => - fromOrganizations.getOrganizationGroupsByKey(state.organizations, key); - -export const getMyOrganizations = state => - fromOrganizations.getMyOrganizations(state.organizations); - -export const areThereCustomOrganizations = state => getAppState(state).organizationsEnabled; - -export const getPermissionsAppUsers = state => fromPermissionsApp.getUsers(state.permissionsApp); - -export const getPermissionsAppGroups = state => fromPermissionsApp.getGroups(state.permissionsApp); - -export const isPermissionsAppLoading = state => fromPermissionsApp.isLoading(state.permissionsApp); - -export const getPermissionsAppQuery = state => fromPermissionsApp.getQuery(state.permissionsApp); - -export const getPermissionsAppFilter = state => fromPermissionsApp.getFilter(state.permissionsApp); - -export const getPermissionsAppSelectedPermission = state => - fromPermissionsApp.getSelectedPermission(state.permissionsApp); - -export const getPermissionsAppError = state => fromPermissionsApp.getError(state.permissionsApp); - -export const getGlobalSettingValue = (state, key) => - fromSettingsApp.getValue(state.settingsApp, key); - -export const getSettingsAppDefinition = (state, key) => - fromSettingsApp.getDefinition(state.settingsApp, key); - -export const getSettingsAppAllCategories = state => - fromSettingsApp.getAllCategories(state.settingsApp); - -export const getSettingsAppDefaultCategory = state => - fromSettingsApp.getDefaultCategory(state.settingsApp); - -export const getSettingsAppSettingsForCategory = (state, category, componentKey) => - fromSettingsApp.getSettingsForCategory(state.settingsApp, category, componentKey); - -export const getSettingsAppChangedValue = (state, key) => - fromSettingsApp.getChangedValue(state.settingsApp, key); - -export const isSettingsAppLoading = (state, key) => - fromSettingsApp.isLoading(state.settingsApp, key); - -export const getSettingsAppValidationMessage = (state, key) => - fromSettingsApp.getValidationMessage(state.settingsApp, key); - -export const getSettingsAppEncryptionState = state => - fromSettingsApp.getEncryptionState(state.settingsApp); - -export const getProjectAdminProjectModules = (state, projectKey) => - fromProjectAdminApp.getProjectModules(state.projectAdminApp, projectKey); diff --git a/server/sonar-web/src/main/js/store/rootReducer.ts b/server/sonar-web/src/main/js/store/rootReducer.ts new file mode 100644 index 00000000000..8dfc49d857f --- /dev/null +++ b/server/sonar-web/src/main/js/store/rootReducer.ts @@ -0,0 +1,166 @@ +/* + * 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 { combineReducers } from 'redux'; +import appState from './appState'; +import globalMessages, * as fromGlobalMessages from './globalMessages'; +import languages, * as fromLanguages from './languages'; +import metrics, * as fromMetrics from './metrics'; +import organizations, * as fromOrganizations from './organizations'; +import users, * as fromUsers from './users'; +import { AppState } from '../app/types'; +import permissionsApp, * as fromPermissionsApp from '../apps/permissions/shared/store/rootReducer'; +import projectAdminApp, * as fromProjectAdminApp from '../apps/project-admin/store/rootReducer'; +import settingsApp, * as fromSettingsApp from '../apps/settings/store/rootReducer'; + +export type Store = { + appState: AppState; + globalMessages: fromGlobalMessages.State; + languages: fromLanguages.Languages; + metrics: fromMetrics.State; + organizations: fromOrganizations.State; + users: fromUsers.State; + + // apps + permissionsApp: any; + projectAdminApp: any; + settingsApp: any; +}; + +export default combineReducers<Store>({ + appState, + globalMessages, + languages, + metrics, + organizations, + users, + + // apps + permissionsApp, + projectAdminApp, + settingsApp +}); + +export function getAppState(state: Store) { + return state.appState; +} + +export function getGlobalMessages(state: Store) { + return fromGlobalMessages.getGlobalMessages(state.globalMessages); +} + +export function getLanguages(state: Store) { + return fromLanguages.getLanguages(state.languages); +} + +export function getCurrentUser(state: Store) { + return fromUsers.getCurrentUser(state.users); +} + +export function getMetrics(state: Store) { + return fromMetrics.getMetrics(state.metrics); +} + +export function getMetricsKey(state: Store) { + return fromMetrics.getMetricsKey(state.metrics); +} + +export function getOrganizationByKey(state: Store, key: string) { + return fromOrganizations.getOrganizationByKey(state.organizations, key); +} + +export function getMyOrganizations(state: Store) { + return fromOrganizations.getMyOrganizations(state.organizations); +} + +export function areThereCustomOrganizations(state: Store) { + return getAppState(state).organizationsEnabled; +} + +export function getPermissionsAppUsers(state: Store) { + return fromPermissionsApp.getUsers(state.permissionsApp); +} + +export function getPermissionsAppGroups(state: Store) { + return fromPermissionsApp.getGroups(state.permissionsApp); +} + +export function isPermissionsAppLoading(state: Store) { + return fromPermissionsApp.isLoading(state.permissionsApp); +} + +export function getPermissionsAppQuery(state: Store) { + return fromPermissionsApp.getQuery(state.permissionsApp); +} + +export function getPermissionsAppFilter(state: Store) { + return fromPermissionsApp.getFilter(state.permissionsApp); +} + +export function getPermissionsAppSelectedPermission(state: Store) { + return fromPermissionsApp.getSelectedPermission(state.permissionsApp); +} + +export function getPermissionsAppError(state: Store) { + return fromPermissionsApp.getError(state.permissionsApp); +} + +export function getGlobalSettingValue(state: Store, key: string) { + return fromSettingsApp.getValue(state.settingsApp, key); +} + +export function getSettingsAppDefinition(state: Store, key: string) { + return fromSettingsApp.getDefinition(state.settingsApp, key); +} + +export function getSettingsAppAllCategories(state: Store) { + return fromSettingsApp.getAllCategories(state.settingsApp); +} + +export function getSettingsAppDefaultCategory(state: Store) { + return fromSettingsApp.getDefaultCategory(state.settingsApp); +} + +export function getSettingsAppSettingsForCategory( + state: Store, + category: string, + componentKey: string +) { + return fromSettingsApp.getSettingsForCategory(state.settingsApp, category, componentKey); +} + +export function getSettingsAppChangedValue(state: Store, key: string) { + return fromSettingsApp.getChangedValue(state.settingsApp, key); +} + +export function isSettingsAppLoading(state: Store, key: string) { + return fromSettingsApp.isLoading(state.settingsApp, key); +} + +export function getSettingsAppValidationMessage(state: Store, key: string) { + return fromSettingsApp.getValidationMessage(state.settingsApp, key); +} + +export function getSettingsAppEncryptionState(state: Store) { + return fromSettingsApp.getEncryptionState(state.settingsApp); +} + +export function getProjectAdminProjectModules(state: Store, projectKey: string) { + return fromProjectAdminApp.getProjectModules(state.projectAdminApp, projectKey); +} diff --git a/server/sonar-web/src/main/js/store/users.ts b/server/sonar-web/src/main/js/store/users.ts new file mode 100644 index 00000000000..969cf8a6f7e --- /dev/null +++ b/server/sonar-web/src/main/js/store/users.ts @@ -0,0 +1,105 @@ +/* + * 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 } from 'lodash'; +import { Dispatch, combineReducers } from 'redux'; +import { Store } from './rootReducer'; +import { ActionType } from './utils/actions'; +import * as api from '../api/users'; +import { CurrentUser, HomePage, isLoggedIn, LoggedInUser } from '../app/types'; + +export function receiveCurrentUser(user: CurrentUser) { + return { type: 'RECEIVE_CURRENT_USER', user }; +} + +export function skipOnboarding() { + return { type: 'SKIP_ONBOARDING' }; +} + +function setHomePageAction(homepage: HomePage) { + return { type: 'SET_HOMEPAGE', homepage }; +} + +export function setHomePage(homepage: HomePage) { + return (dispatch: Dispatch<Store>) => { + api.setHomePage(homepage).then( + () => { + dispatch(setHomePageAction(homepage)); + }, + () => {} + ); + }; +} + +type Action = + | ActionType<typeof receiveCurrentUser, 'RECEIVE_CURRENT_USER'> + | ActionType<typeof skipOnboarding, 'SKIP_ONBOARDING'> + | ActionType<typeof setHomePageAction, 'SET_HOMEPAGE'>; + +export interface State { + usersByLogin: { [login: string]: any }; + userLogins: string[]; + currentUser: CurrentUser; +} + +function usersByLogin(state: State['usersByLogin'] = {}, action: Action): State['usersByLogin'] { + if (action.type === 'RECEIVE_CURRENT_USER' && isLoggedIn(action.user)) { + return { ...state, [action.user.login]: action.user }; + } else { + return state; + } +} + +function userLogins(state: State['userLogins'] = [], action: Action): State['userLogins'] { + if (action.type === 'RECEIVE_CURRENT_USER' && isLoggedIn(action.user)) { + return uniq([...state, action.user.login]); + } else { + return state; + } +} + +function currentUser( + state: State['currentUser'] = { isLoggedIn: false }, + action: Action +): State['currentUser'] { + if (action.type === 'RECEIVE_CURRENT_USER') { + return action.user; + } + if (action.type === 'SKIP_ONBOARDING' && isLoggedIn(state)) { + return { ...state, showOnboardingTutorial: false } as LoggedInUser; + } + if (action.type === 'SET_HOMEPAGE' && isLoggedIn(state)) { + return { ...state, homepage: action.homepage } as LoggedInUser; + } + return state; +} + +export default combineReducers({ usersByLogin, userLogins, currentUser }); + +export function getCurrentUser(state: State) { + return state.currentUser; +} + +export function getUserByLogin(state: State, login: string) { + return state.usersByLogin[login]; +} + +export function getUsersByLogins(state: State, logins: string[]) { + return logins.map(login => getUserByLogin(state, login)); +} diff --git a/server/sonar-web/src/main/js/store/users/actions.ts b/server/sonar-web/src/main/js/store/users/actions.ts deleted file mode 100644 index 9c9a146e2a4..00000000000 --- a/server/sonar-web/src/main/js/store/users/actions.ts +++ /dev/null @@ -1,49 +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 { Dispatch } from 'redux'; -import * as api from '../../api/users'; -import { CurrentUser, HomePage } from '../../app/types'; - -export const RECEIVE_CURRENT_USER = 'RECEIVE_CURRENT_USER'; -export const SKIP_ONBOARDING = 'SKIP_ONBOARDING'; -export const SET_HOMEPAGE = 'SET_HOMEPAGE'; - -export const receiveCurrentUser = (user: CurrentUser) => ({ - type: RECEIVE_CURRENT_USER, - user -}); - -export const skipOnboarding = () => ({ type: SKIP_ONBOARDING }); - -export const fetchCurrentUser = () => (dispatch: Dispatch<any>) => { - return api.getCurrentUser().then(user => { - dispatch(receiveCurrentUser(user)); - return user; - }); -}; - -export const setHomePage = (homepage: HomePage) => (dispatch: Dispatch<any>) => { - api.setHomePage(homepage).then( - () => { - dispatch({ type: SET_HOMEPAGE, homepage }); - }, - () => {} - ); -}; diff --git a/server/sonar-web/src/main/js/store/users/reducer.ts b/server/sonar-web/src/main/js/store/users/reducer.ts deleted file mode 100644 index a6e79db6d97..00000000000 --- a/server/sonar-web/src/main/js/store/users/reducer.ts +++ /dev/null @@ -1,71 +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 { combineReducers } from 'redux'; -import { uniq } from 'lodash'; -import { RECEIVE_CURRENT_USER, SKIP_ONBOARDING, SET_HOMEPAGE } from './actions'; -import { CurrentUser } from '../../app/types'; - -interface UsersByLogin { - [login: string]: any; -} - -const usersByLogin = (state: UsersByLogin = {}, action: any = {}) => { - if (action.type === RECEIVE_CURRENT_USER) { - return { ...state, [action.user.login]: action.user }; - } else { - return state; - } -}; - -type UserLogins = string[]; - -const userLogins = (state: UserLogins = [], action: any = {}) => { - if (action.type === RECEIVE_CURRENT_USER) { - return uniq([...state, action.user.login]); - } else { - return state; - } -}; - -const currentUser = (state: CurrentUser | null = null, action: any = {}) => { - if (action.type === RECEIVE_CURRENT_USER) { - return action.user; - } - if (action.type === SKIP_ONBOARDING) { - return state ? { ...state, showOnboardingTutorial: false } : null; - } - if (action.type === SET_HOMEPAGE) { - return state && { ...state, homepage: action.homepage }; - } - return state; -}; - -interface State { - usersByLogin: UsersByLogin; - userLogins: UserLogins; - currentUser: CurrentUser | null; -} - -export default combineReducers({ usersByLogin, userLogins, currentUser }); - -export const getCurrentUser = (state: State) => state.currentUser!; -export const getUserByLogin = (state: State, login: string) => state.usersByLogin[login]; -export const getUsersByLogins = (state: State, logins: string[]) => - logins.map(login => getUserByLogin(state, login)); diff --git a/server/sonar-web/src/main/js/store/languages/actions.js b/server/sonar-web/src/main/js/store/utils/actions.ts index 9b3d1a9d506..4926a67d2a3 100644 --- a/server/sonar-web/src/main/js/store/languages/actions.js +++ b/server/sonar-web/src/main/js/store/utils/actions.ts @@ -17,9 +17,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -export const RECEIVE_LANGUAGES = 'RECEIVE_LANGUAGES'; +import { Omit } from '../../app/types'; -export const receiveLanguages = languages => ({ - type: RECEIVE_LANGUAGES, - languages -}); +type ActionCreator = (...args: any[]) => { type: string }; + +export type ActionType<F extends ActionCreator, T> = Omit<ReturnType<F>, 'type'> & { type: T }; diff --git a/server/sonar-web/src/main/js/store/utils/configureStore.js b/server/sonar-web/src/main/js/store/utils/configureStore.ts index 75bb516bfbe..8681815877f 100644 --- a/server/sonar-web/src/main/js/store/utils/configureStore.js +++ b/server/sonar-web/src/main/js/store/utils/configureStore.ts @@ -20,6 +20,9 @@ import { createStore, applyMiddleware, compose } from 'redux'; import thunk from 'redux-thunk'; +type RootReducer = typeof import('../rootReducer').default; +type State = import('../rootReducer').Store; + const middlewares = [thunk]; const composed = []; @@ -27,7 +30,8 @@ if (process.env.NODE_ENV === 'development') { const { createLogger } = require('redux-logger'); middlewares.push(createLogger()); - composed.push(window.devToolsExtension ? window.devToolsExtension() : f => f); + const { devToolsExtension } = window as any; + composed.push(devToolsExtension ? devToolsExtension() : (f: Function) => f); } const finalCreateStore = compose( @@ -35,6 +39,6 @@ const finalCreateStore = compose( ...composed )(createStore); -export default function configureStore(rootReducer, initialState) { +export default function configureStore(rootReducer: RootReducer, initialState?: State) { return finalCreateStore(rootReducer, initialState); } |