Browse Source

SONAR-13147 lazyloading

tags/8.3.0.34182
Jeremy Davis 4 years ago
parent
commit
85c94cb261
69 changed files with 630 additions and 454 deletions
  1. 2
    2
      server/sonar-web/src/main/js/app/components/App.tsx
  2. 2
    2
      server/sonar-web/src/main/js/app/components/SimpleSessionsContainer.tsx
  3. 5
    3
      server/sonar-web/src/main/js/app/components/StartupModal.tsx
  4. 2
    2
      server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx
  5. 4
    3
      server/sonar-web/src/main/js/app/components/nav/component/ComponentNavWarnings.tsx
  6. 1
    1
      server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavWarnings-test.tsx.snap
  7. 4
    4
      server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx
  8. 1
    1
      server/sonar-web/src/main/js/app/components/nav/global/GlobalNavPlus.tsx
  9. 3
    3
      server/sonar-web/src/main/js/app/components/search/Search.tsx
  10. 35
    20
      server/sonar-web/src/main/js/app/utils/startReactApp.tsx
  11. 4
    2
      server/sonar-web/src/main/js/apps/about/routes.ts
  12. 7
    7
      server/sonar-web/src/main/js/apps/account/routes.ts
  13. 2
    2
      server/sonar-web/src/main/js/apps/background-tasks/components/TaskActions.tsx
  14. 2
    2
      server/sonar-web/src/main/js/apps/background-tasks/routes.ts
  15. 2
    2
      server/sonar-web/src/main/js/apps/code/routes.ts
  16. 2
    2
      server/sonar-web/src/main/js/apps/coding-rules/routes.ts
  17. 2
    2
      server/sonar-web/src/main/js/apps/component-measures/routes.ts
  18. 2
    2
      server/sonar-web/src/main/js/apps/custom-measures/routes.ts
  19. 2
    2
      server/sonar-web/src/main/js/apps/custom-metrics/routes.ts
  20. 2
    2
      server/sonar-web/src/main/js/apps/documentation/routes.ts
  21. 2
    2
      server/sonar-web/src/main/js/apps/groups/routes.ts
  22. 0
    37
      server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx
  23. 0
    56
      server/sonar-web/src/main/js/apps/issues/__tests__/IssuesPageSelector-test.tsx
  24. 0
    17
      server/sonar-web/src/main/js/apps/issues/__tests__/__snapshots__/IssuesPageSelector-test.tsx.snap
  25. 9
    14
      server/sonar-web/src/main/js/apps/issues/components/App.tsx
  26. 10
    10
      server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx
  27. 0
    3
      server/sonar-web/src/main/js/apps/issues/components/IssuesSourceViewer.tsx
  28. 3
    3
      server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.tsx
  29. 0
    5
      server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesSourceViewer-test.tsx.snap
  30. 2
    2
      server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewer.tsx
  31. 3
    3
      server/sonar-web/src/main/js/apps/maintenance/routes.tsx
  32. 5
    2
      server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx
  33. 1
    1
      server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap
  34. 2
    2
      server/sonar-web/src/main/js/apps/marketplace/routes.ts
  35. 1
    5
      server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx
  36. 29
    13
      server/sonar-web/src/main/js/apps/organizations/routes.ts
  37. 3
    3
      server/sonar-web/src/main/js/apps/overview/components/App.tsx
  38. 16
    5
      server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx
  39. 2
    2
      server/sonar-web/src/main/js/apps/overview/routes.ts
  40. 2
    2
      server/sonar-web/src/main/js/apps/permission-templates/routes.ts
  41. 3
    3
      server/sonar-web/src/main/js/apps/permissions/routes.ts
  42. 2
    2
      server/sonar-web/src/main/js/apps/portfolio/routes.ts
  43. 2
    2
      server/sonar-web/src/main/js/apps/projectActivity/routes.ts
  44. 2
    2
      server/sonar-web/src/main/js/apps/projectBaseline/routes.ts
  45. 2
    2
      server/sonar-web/src/main/js/apps/projectBranches/routes.ts
  46. 2
    2
      server/sonar-web/src/main/js/apps/projectQualityGate/routes.ts
  47. 2
    2
      server/sonar-web/src/main/js/apps/projectQualityProfiles/routes.ts
  48. 2
    2
      server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx
  49. 2
    14
      server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx
  50. 2
    2
      server/sonar-web/src/main/js/apps/projects/routes.ts
  51. 2
    2
      server/sonar-web/src/main/js/apps/projectsManagement/routes.ts
  52. 2
    2
      server/sonar-web/src/main/js/apps/quality-gates/routes.ts
  53. 2
    2
      server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResultActivation.tsx
  54. 7
    7
      server/sonar-web/src/main/js/apps/quality-profiles/routes.ts
  55. 5
    5
      server/sonar-web/src/main/js/apps/sessions/routes.ts
  56. 3
    3
      server/sonar-web/src/main/js/apps/settings/routes.ts
  57. 2
    2
      server/sonar-web/src/main/js/apps/system/routes.ts
  58. 2
    5
      server/sonar-web/src/main/js/apps/tutorials/routes.ts
  59. 2
    2
      server/sonar-web/src/main/js/apps/users/routes.ts
  60. 3
    3
      server/sonar-web/src/main/js/apps/web-api/routes.ts
  61. 2
    2
      server/sonar-web/src/main/js/apps/webhooks/routes.ts
  62. 2
    2
      server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx
  63. 99
    103
      server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx
  64. 127
    4
      server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerBase-test.tsx
  65. 158
    15
      server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerBase-test.tsx.snap
  66. 2
    2
      server/sonar-web/src/main/js/components/controls/DateInput.tsx
  67. 2
    2
      server/sonar-web/src/main/js/components/docs/DocTooltip.tsx
  68. 1
    1
      server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap
  69. 10
    4
      server/sonar-web/src/main/js/components/workspace/Workspace.tsx

+ 2
- 2
server/sonar-web/src/main/js/app/components/App.tsx View File

@@ -19,14 +19,14 @@
*/
import * as React from 'react';
import { connect } from 'react-redux';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { fetchMyOrganizations } from '../../apps/account/organizations/actions';
import { isSonarCloud } from '../../helpers/system';
import { isLoggedIn } from '../../helpers/users';
import { fetchLanguages } from '../../store/rootActions';
import { getAppState, getCurrentUser, getGlobalSettingValue, Store } from '../../store/rootReducer';

const PageTracker = lazyLoad(() => import('./PageTracker'));
const PageTracker = lazyLoadComponent(() => import('./PageTracker'));

interface StateProps {
appState: T.AppState | undefined;

+ 2
- 2
server/sonar-web/src/main/js/app/components/SimpleSessionsContainer.tsx View File

@@ -18,10 +18,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import GlobalFooterContainer from './GlobalFooterContainer';

const PageTracker = lazyLoad(() => import('./PageTracker'));
const PageTracker = lazyLoadComponent(() => import('./PageTracker'));

interface Props {
children?: React.ReactNode;

+ 5
- 3
server/sonar-web/src/main/js/app/components/StartupModal.tsx View File

@@ -20,7 +20,7 @@
import * as differenceInDays from 'date-fns/difference_in_days';
import * as React from 'react';
import { connect } from 'react-redux';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { parseDate, toShortNotSoISOString } from 'sonar-ui-common/helpers/dates';
import { hasMessage } from 'sonar-ui-common/helpers/l10n';
import { get, save } from 'sonar-ui-common/helpers/storage';
@@ -33,8 +33,10 @@ import { skipOnboarding } from '../../store/users';
import { EditionKey } from '../../types/editions';
import { OnboardingContext } from './OnboardingContext';

const OnboardingModal = lazyLoad(() => import('../../apps/tutorials/onboarding/OnboardingModal'));
const LicensePromptModal = lazyLoad(
const OnboardingModal = lazyLoadComponent(() =>
import('../../apps/tutorials/onboarding/OnboardingModal')
);
const LicensePromptModal = lazyLoadComponent(
() => import('../../apps/marketplace/components/LicensePromptModal'),
'LicensePromptModal'
);

+ 2
- 2
server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx View File

@@ -21,10 +21,10 @@ import * as React from 'react';
import { ButtonLink } from 'sonar-ui-common/components/controls/buttons';
import Toggler from 'sonar-ui-common/components/controls/Toggler';
import HelpIcon from 'sonar-ui-common/components/icons/HelpIcon';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { translate } from 'sonar-ui-common/helpers/l10n';

const EmbedDocsPopup = lazyLoad(() => import('./EmbedDocsPopup'));
const EmbedDocsPopup = lazyLoadComponent(() => import('./EmbedDocsPopup'));

interface State {
helpOpen: boolean;

+ 4
- 3
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavWarnings.tsx View File

@@ -19,12 +19,13 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { Alert } from 'sonar-ui-common/components/ui/Alert';
import { translate } from 'sonar-ui-common/helpers/l10n';

const AnalysisWarningsModal = lazyLoad(() =>
import('../../../../components/common/AnalysisWarningsModal')
const AnalysisWarningsModal = lazyLoadComponent(
() => import('../../../../components/common/AnalysisWarningsModal'),
'AnalysisWarningsModal'
);

interface Props {

+ 1
- 1
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavWarnings-test.tsx.snap View File

@@ -30,7 +30,7 @@ exports[`should render 1`] = `
}
/>
</Alert>
<LazyLoader
<AnalysisWarningsModal
onClose={[Function]}
warnings={
Array [

+ 4
- 4
server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx View File

@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { connect } from 'react-redux';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import NavBar from 'sonar-ui-common/components/ui/NavBar';
import { parseDate } from 'sonar-ui-common/helpers/dates';
import {
@@ -47,12 +47,12 @@ import GlobalNavExplore from './GlobalNavExplore';
import GlobalNavMenu from './GlobalNavMenu';
import GlobalNavUserContainer from './GlobalNavUserContainer';

const GlobalNavPlus = lazyLoad(() => import('./GlobalNavPlus'), 'GlobalNavPlus');
const NotificationsSidebar = lazyLoad(
const GlobalNavPlus = lazyLoadComponent(() => import('./GlobalNavPlus'), 'GlobalNavPlus');
const NotificationsSidebar = lazyLoadComponent(
() => import('../../notifications/NotificationsSidebar'),
'NotificationsSidebar'
);
const NavLatestNotification = lazyLoad(
const NavLatestNotification = lazyLoadComponent(
() => import('../../notifications/NavLatestNotification'),
'NavLatestNotification'
);

+ 1
- 1
server/sonar-web/src/main/js/app/components/nav/global/GlobalNavPlus.tsx View File

@@ -200,4 +200,4 @@ export class GlobalNavPlus extends React.PureComponent<Props & WithRouterProps,
}
}

export default withRouter(GlobalNavPlus);
export default withRouter<Props>(GlobalNavPlus);

+ 3
- 3
server/sonar-web/src/main/js/app/components/search/Search.tsx View File

@@ -26,7 +26,7 @@ import { DropdownOverlay } from 'sonar-ui-common/components/controls/Dropdown';
import OutsideClickHandler from 'sonar-ui-common/components/controls/OutsideClickHandler';
import SearchBox from 'sonar-ui-common/components/controls/SearchBox';
import ClockIcon from 'sonar-ui-common/components/icons/ClockIcon';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import { scrollToElement } from 'sonar-ui-common/helpers/scrolling';
@@ -36,8 +36,8 @@ import RecentHistory from '../RecentHistory';
import './Search.css';
import { ComponentResult, More, Results, sortQualifiers } from './utils';

const SearchResults = lazyLoad(() => import('./SearchResults'));
const SearchResult = lazyLoad(() => import('./SearchResult'));
const SearchResults = lazyLoadComponent(() => import('./SearchResults'));
const SearchResult = lazyLoadComponent(() => import('./SearchResult'));

interface OwnProps {
appState: Pick<T.AppState, 'organizationsEnabled'>;

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

@@ -26,7 +26,6 @@ import { HelmetProvider } from 'react-helmet-async';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
import { IndexRoute, Redirect, Route, RouteConfig, RouteProps, Router } from 'react-router';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { ThemeProvider } from 'sonar-ui-common/components/theme';
import getHistory from 'sonar-ui-common/helpers/getHistory';
@@ -44,7 +43,6 @@ import ExploreIssues from '../../apps/explore/ExploreIssues';
import ExploreProjects from '../../apps/explore/ExploreProjects';
import groupsRoutes from '../../apps/groups/routes';
import Issues from '../../apps/issues/components/AppContainer';
import IssuesPageSelector from '../../apps/issues/IssuesPageSelector';
import { maintenanceRoutes, setupRoutes } from '../../apps/maintenance/routes';
import marketplaceRoutes from '../../apps/marketplace/routes';
import organizationsRoutes from '../../apps/organizations/routes';
@@ -151,7 +149,7 @@ function renderRedirects() {

function renderComponentRoutes() {
return (
<Route component={lazyLoad(() => import('../components/ComponentContainer'))}>
<Route component={lazyLoadComponent(() => import('../components/ComponentContainer'))}>
<RouteWithChildRoutes path="code" childRoutes={codeRoutes} />
<RouteWithChildRoutes path="component_measures" childRoutes={componentMeasuresRoutes} />
<RouteWithChildRoutes path="dashboard" childRoutes={overviewRoutes} />
@@ -159,7 +157,7 @@ function renderComponentRoutes() {
<RouteWithChildRoutes path="project/activity" childRoutes={projectActivityRoutes} />
<Route
path="project/extension/:pluginKey/:extensionKey"
component={lazyLoad(() => import('../components/extensions/ProjectPageExtension'))}
component={lazyLoadComponent(() => import('../components/extensions/ProjectPageExtension'))}
/>
<Route
path="project/issues"
@@ -191,11 +189,13 @@ function renderComponentRoutes() {
path="project/quality_profiles"
childRoutes={projectQualityProfilesRoutes}
/>
<Route component={lazyLoad(() => import('../components/ProjectAdminContainer'))}>
<Route component={lazyLoadComponent(() => import('../components/ProjectAdminContainer'))}>
<RouteWithChildRoutes path="custom_measures" childRoutes={customMeasuresRoutes} />
<Route
path="project/admin/extension/:pluginKey/:extensionKey"
component={lazyLoad(() => import('../components/extensions/ProjectAdminPageExtension'))}
component={lazyLoadComponent(() =>
import('../components/extensions/ProjectAdminPageExtension')
)}
/>
<RouteWithChildRoutes path="project/background_tasks" childRoutes={backgroundTasksRoutes} />
<RouteWithChildRoutes path="project/baseline" childRoutes={projectBaselineRoutes} />
@@ -205,13 +205,16 @@ function renderComponentRoutes() {
<RouteWithChildRoutes path="project/webhooks" childRoutes={webhooksRoutes} />
<Route
path="project/deletion"
component={lazyLoad(() => import('../../apps/projectDeletion/App'))}
component={lazyLoadComponent(() => import('../../apps/projectDeletion/App'))}
/>
<Route
path="project/links"
component={lazyLoad(() => import('../../apps/projectLinks/App'))}
component={lazyLoadComponent(() => import('../../apps/projectLinks/App'))}
/>
<Route
path="project/key"
component={lazyLoadComponent(() => import('../../apps/projectKey/Key'))}
/>
<Route path="project/key" component={lazyLoad(() => import('../../apps/projectKey/Key'))} />
</Route>
</Route>
);
@@ -219,10 +222,12 @@ function renderComponentRoutes() {

function renderAdminRoutes() {
return (
<Route component={lazyLoad(() => import('../components/AdminContainer'))} path="admin">
<Route component={lazyLoadComponent(() => import('../components/AdminContainer'))} path="admin">
<Route
path="extension/:pluginKey/:extensionKey"
component={lazyLoad(() => import('../components/extensions/GlobalAdminPageExtension'))}
component={lazyLoadComponent(() =>
import('../components/extensions/GlobalAdminPageExtension')
)}
/>
<RouteWithChildRoutes path="background_tasks" childRoutes={backgroundTasksRoutes} />
<RouteWithChildRoutes path="custom_metrics" childRoutes={customMetricsRoutes} />
@@ -259,21 +264,26 @@ export default function startReactApp(

<Route
path="markdown/help"
component={lazyLoad(() => import('../components/MarkdownHelp'))}
component={lazyLoadComponent(() => import('../components/MarkdownHelp'))}
/>

<Route component={lazyLoad(() => import('../components/SimpleContainer'))}>
<Route component={lazyLoadComponent(() => import('../components/SimpleContainer'))}>
<Route path="maintenance">{maintenanceRoutes}</Route>
<Route path="setup">{setupRoutes}</Route>
</Route>

<Route component={MigrationContainer}>
<Route component={lazyLoad(() => import('../components/SimpleSessionsContainer'))}>
<Route
component={lazyLoadComponent(() =>
import('../components/SimpleSessionsContainer')
)}>
<RouteWithChildRoutes path="/sessions" childRoutes={sessionsRoutes} />
</Route>

<Route path="/" component={App}>
<IndexRoute component={lazyLoad(() => import('../components/Landing'))} />
<IndexRoute
component={lazyLoadComponent(() => import('../components/Landing'))}
/>
<RouteWithChildRoutes path="about" childRoutes={aboutRoutes} />

<Route component={GlobalContainer}>
@@ -286,18 +296,20 @@ export default function startReactApp(
</Route>
<Route
path="extension/:pluginKey/:extensionKey"
component={lazyLoad(() =>
component={lazyLoadComponent(() =>
import('../components/extensions/GlobalPageExtension')
)}
/>
<Route path="issues" component={IssuesPageSelector} />
<Route path="issues" component={Issues} />
<RouteWithChildRoutes path="onboarding" childRoutes={onboardingRoutes} />
<RouteWithChildRoutes path="organizations" childRoutes={organizationsRoutes} />
<RouteWithChildRoutes path="projects" childRoutes={projectsRoutes} />
<RouteWithChildRoutes path="quality_gates" childRoutes={qualityGatesRoutes} />
<Route
path="portfolios"
component={lazyLoad(() => import('../components/extensions/PortfoliosPage'))}
component={lazyLoadComponent(() =>
import('../components/extensions/PortfoliosPage')
)}
/>
<RouteWithChildRoutes path="profiles" childRoutes={qualityProfilesRoutes} />
<RouteWithChildRoutes path="web_api" childRoutes={webAPIRoutes} />
@@ -308,9 +320,12 @@ export default function startReactApp(
</Route>
<Route
path="not_found"
component={lazyLoad(() => import('../components/NotFound'))}
component={lazyLoadComponent(() => import('../components/NotFound'))}
/>
<Route
path="*"
component={lazyLoadComponent(() => import('../components/NotFound'))}
/>
<Route path="*" component={lazyLoad(() => import('../components/NotFound'))} />
</Route>
</Route>
</Router>

+ 4
- 2
server/sonar-web/src/main/js/apps/about/routes.ts View File

@@ -17,8 +17,10 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [{ indexRoute: { component: lazyLoad(() => import('./components/AboutApp')) } }];
const routes = [
{ indexRoute: { component: lazyLoadComponent(() => import('./components/AboutApp')) } }
];

export default routes;

+ 7
- 7
server/sonar-web/src/main/js/apps/account/routes.ts View File

@@ -17,30 +17,30 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
component: lazyLoad(() => import('./components/Account')),
component: lazyLoadComponent(() => import('./components/Account')),
childRoutes: [
{
indexRoute: { component: lazyLoad(() => import('./profile/Profile')) }
indexRoute: { component: lazyLoadComponent(() => import('./profile/Profile')) }
},
{
path: 'security',
component: lazyLoad(() => import('./components/Security'))
component: lazyLoadComponent(() => import('./components/Security'))
},
{
path: 'projects',
component: lazyLoad(() => import('./projects/ProjectsContainer'))
component: lazyLoadComponent(() => import('./projects/ProjectsContainer'))
},
{
path: 'notifications',
component: lazyLoad(() => import('./notifications/Notifications'))
component: lazyLoadComponent(() => import('./notifications/Notifications'))
},
{
path: 'organizations',
component: lazyLoad(() => import('./organizations/UserOrganizations'))
component: lazyLoadComponent(() => import('./organizations/UserOrganizations'))
}
]
}

+ 2
- 2
server/sonar-web/src/main/js/apps/background-tasks/components/TaskActions.tsx View File

@@ -22,13 +22,13 @@ import ActionsDropdown, {
ActionsDropdownItem
} from 'sonar-ui-common/components/controls/ActionsDropdown';
import ConfirmModal from 'sonar-ui-common/components/controls/ConfirmModal';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import { STATUSES } from '../constants';
import ScannerContext from './ScannerContext';
import Stacktrace from './Stacktrace';

const AnalysisWarningsModal = lazyLoad(
const AnalysisWarningsModal = lazyLoadComponent(
() => import('../../../components/common/AnalysisWarningsModal'),
'AnalysisWarningsModal'
);

+ 2
- 2
server/sonar-web/src/main/js/apps/background-tasks/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/BackgroundTasksApp')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/BackgroundTasksApp')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/code/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/coding-rules/routes.ts View File

@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { RedirectFunction, RouterState } from 'react-router';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { parseQuery, serializeQuery } from './query';

function parseHash(hash: string): T.RawQuery {
@@ -47,7 +47,7 @@ const routes = [
replace({ pathname: nextState.location.pathname, query: normalizedQuery });
}
},
component: lazyLoad(() => import('./components/App'))
component: lazyLoadComponent(() => import('./components/App'))
}
}
];

+ 2
- 2
server/sonar-web/src/main/js/apps/component-measures/routes.ts View File

@@ -18,11 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { RedirectFunction, RouterState } from 'react-router';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
},
{
path: 'domain/:domainName',

+ 2
- 2
server/sonar-web/src/main/js/apps/custom-measures/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
}
];


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

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/documentation/routes.ts View File

@@ -17,9 +17,9 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const App = lazyLoad(() => import(/* webpackChunkName: "docs" */ './components/App'));
const App = lazyLoadComponent(() => import(/* webpackChunkName: "docs" */ './components/App'));

const routes = [{ indexRoute: { component: App } }, { path: '**', indexRoute: { component: App } }];


+ 2
- 2
server/sonar-web/src/main/js/apps/groups/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
}
];


+ 0
- 37
server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx View File

@@ -1,37 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2020 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { withCurrentUser } from '../../components/hoc/withCurrentUser';
import { Location } from '../../components/hoc/withRouter';
import { isSonarCloud } from '../../helpers/system';
import { isLoggedIn } from '../../helpers/users';
import AppContainer from './components/AppContainer';

export interface Props {
currentUser: T.CurrentUser;
location: Location;
}

export function IssuesPage({ currentUser, location }: Props) {
const myIssues = (isLoggedIn(currentUser) && isSonarCloud()) || undefined;
return <AppContainer location={location} myIssues={myIssues} />;
}

export default withCurrentUser(IssuesPage);

+ 0
- 56
server/sonar-web/src/main/js/apps/issues/__tests__/IssuesPageSelector-test.tsx View File

@@ -1,56 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2020 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { shallow } from 'enzyme';
import * as React from 'react';
import { isSonarCloud } from '../../../helpers/system';
import { mockCurrentUser, mockLocation, mockLoggedInUser } from '../../../helpers/testMocks';
import { IssuesPage, Props } from '../IssuesPageSelector';

jest.mock('../../../helpers/system', () => ({ isSonarCloud: jest.fn().mockReturnValue(false) }));

it('should render normal issues page', () => {
expect(shallowRender()).toMatchSnapshot();
expect(
shallowRender({ currentUser: mockLoggedInUser() })
.find('Connect(IssuesAppContainer)')
.prop('myIssues')
).toBeFalsy();
(isSonarCloud as jest.Mock).mockReturnValueOnce(true);
expect(
shallowRender()
.find('Connect(IssuesAppContainer)')
.prop('myIssues')
).toBeFalsy();
});

it('should render my issues page', () => {
(isSonarCloud as jest.Mock).mockReturnValueOnce(true);
expect(
shallowRender({ currentUser: mockLoggedInUser() })
.find('Connect(IssuesAppContainer)')
.prop('myIssues')
).toBeTruthy();
});

function shallowRender(props: Partial<Props> = {}) {
return shallow(
<IssuesPage currentUser={mockCurrentUser()} location={mockLocation()} {...props} />
);
}

+ 0
- 17
server/sonar-web/src/main/js/apps/issues/__tests__/__snapshots__/IssuesPageSelector-test.tsx.snap View File

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

exports[`should render normal issues page 1`] = `
<Connect(IssuesAppContainer)
location={
Object {
"action": "PUSH",
"hash": "",
"key": "key",
"pathname": "/path",
"query": Object {},
"search": "",
"state": Object {},
}
}
/>
`;

+ 9
- 14
server/sonar-web/src/main/js/apps/issues/components/App.tsx View File

@@ -22,7 +22,6 @@ import { debounce, keyBy, omit, without } from 'lodash';
import * as React from 'react';
import { Helmet } from 'react-helmet-async';
import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { Button } from 'sonar-ui-common/components/controls/buttons';
import Checkbox from 'sonar-ui-common/components/controls/Checkbox';
import ListFooter from 'sonar-ui-common/components/controls/ListFooter';
@@ -41,7 +40,7 @@ import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import EmptySearch from '../../../components/common/EmptySearch';
import FiltersHeader from '../../../components/common/FiltersHeader';
import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
import { Location, Router } from '../../../components/hoc/withRouter';
import '../../../components/search-navigator.css';
import {
fillBranchLike,
@@ -50,7 +49,6 @@ import {
isSameBranchLike
} from '../../../helpers/branch-like';
import { isSonarCloud } from '../../../helpers/system';
import { fetchBranchStatus } from '../../../store/rootActions';
import { BranchLike } from '../../../types/branch-like';
import * as actions from '../actions';
import ConciseIssuesList from '../conciseIssuesList/ConciseIssuesList';
@@ -104,10 +102,10 @@ interface Props {
fetchBranchStatus: (branchLike: BranchLike, projectKey: string) => Promise<void>;
fetchIssues: (query: T.RawQuery, requestOrganizations?: boolean) => Promise<FetchIssuesPromise>;
hideAuthorFacet?: boolean;
location: Pick<Location, 'pathname' | 'query'>;
location: Location;
multiOrganizations?: boolean;
myIssues?: boolean;
onBranchesChange: () => void;
onBranchesChange?: () => void;
organization?: { key: string };
router: Pick<Router, 'push' | 'replace'>;
userOrganizations: T.Organization[];
@@ -144,7 +142,7 @@ export interface State {
const DEFAULT_QUERY = { resolved: 'false' };
const MAX_INITAL_FETCH = 1000;

export class App extends React.PureComponent<Props, State> {
export default class App extends React.PureComponent<Props, State> {
mounted = false;

constructor(props: Props) {
@@ -539,13 +537,13 @@ export class App extends React.PureComponent<Props, State> {
const { paging } = this.state;

if (!paging) {
return;
return Promise.reject();
}

const p = paging.pageIndex + 1;

this.setState({ checkAll: false, loadingMore: true });
this.fetchIssuesPage(p).then(
return this.fetchIssuesPage(p).then(
response => {
if (this.mounted) {
this.setState(state => ({
@@ -825,8 +823,9 @@ export class App extends React.PureComponent<Props, State> {
handleReload = () => {
this.fetchFirstIssues();
this.refreshBranchStatus();
if (isPullRequest(this.props.branchLike)) {
this.props.onBranchesChange();
const { branchLike, onBranchesChange } = this.props;
if (onBranchesChange && isPullRequest(branchLike)) {
onBranchesChange();
}
};

@@ -1180,7 +1179,3 @@ export class App extends React.PureComponent<Props, State> {
);
}
}

const mapDispatchToProps = { fetchBranchStatus: fetchBranchStatus as any };

export default withRouter(connect(null, mapDispatchToProps)(App));

+ 10
- 10
server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx View File

@@ -20,12 +20,14 @@
import { uniq } from 'lodash';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { searchIssues } from '../../../api/issues';
import { getOrganizations } from '../../../api/organizations';
import throwGlobalError from '../../../app/utils/throwGlobalError';
import { withRouter } from '../../../components/hoc/withRouter';
import { parseIssueFromResponse } from '../../../helpers/issues';
import { receiveOrganizations } from '../../../store/organizations';
import { fetchBranchStatus } from '../../../store/rootActions';
import {
areThereCustomOrganizations,
getCurrentUser,
@@ -33,6 +35,8 @@ import {
Store
} from '../../../store/rootReducer';

const IssuesAppContainer = lazyLoadComponent(() => import('./App'), 'IssuesAppContainer');

interface StateProps {
currentUser: T.CurrentUser;
userOrganizations: T.Organization[];
@@ -79,14 +83,10 @@ const fetchIssues = (query: T.RawQuery, requestOrganizations = true) => (
.catch(throwGlobalError);
};

interface DispatchProps {
fetchIssues: (query: T.RawQuery, requestOrganizations?: boolean) => Promise<void>;
}

// have to type cast this, because of async action
const mapDispatchToProps = { fetchIssues: fetchIssues as any } as DispatchProps;
const mapDispatchToProps = {
fetchBranchStatus: fetchBranchStatus as any,
fetchIssues: fetchIssues as any
};

export default connect(
mapStateToProps,
mapDispatchToProps
)(lazyLoad(() => import('./App'), 'IssuesAppContainer'));
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(IssuesAppContainer));

+ 0
- 3
server/sonar-web/src/main/js/apps/issues/components/IssuesSourceViewer.tsx View File

@@ -17,7 +17,6 @@
* 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 * as React from 'react';
import { scrollToElement } from 'sonar-ui-common/helpers/scrolling';
import SourceViewer from '../../../components/SourceViewer/SourceViewer';
@@ -91,12 +90,10 @@ export default class IssuesSourceViewer extends React.PureComponent<Props> {
: undefined;

if (locations.length > 0) {
const components = uniq(locations.map(l => l.component));
return (
<div ref={node => (this.node = node)}>
<CrossComponentSourceViewer
branchLike={this.props.branchLike}
components={components}
highlightedLocationMessage={highlightedLocationMessage}
issue={openIssue}
issues={this.props.issues}

+ 3
- 3
server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.tsx View File

@@ -38,7 +38,7 @@ import {
selectPreviousFlow,
selectPreviousLocation
} from '../../actions';
import { App } from '../App';
import App from '../App';

jest.mock('sonar-ui-common/helpers/handleRequiredAuthentication', () => ({
default: jest.fn()
@@ -90,7 +90,7 @@ it('should not render for anonymous user', () => {

it('should open standard facets for vulnerabilities and hotspots', () => {
const wrapper = shallowRender({
location: { pathname: '/issues', query: { types: 'VULNERABILITY' } }
location: mockLocation({ pathname: '/issues', query: { types: 'VULNERABILITY' } })
});
const instance = wrapper.instance();
const fetchFacet = jest.spyOn(instance, 'fetchFacet');
@@ -420,7 +420,7 @@ function shallowRender(props: Partial<App['props']> = {}) {
rules: [],
users: []
})}
location={{ pathname: '/issues', query: {} }}
location={mockLocation({ pathname: '/issues', query: {} })}
onBranchesChange={() => {}}
organization={{ key: 'foo' }}
router={mockRouter()}

+ 0
- 5
server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesSourceViewer-test.tsx.snap View File

@@ -11,11 +11,6 @@ exports[`should render CrossComponentSourceViewer correctly 1`] = `
"name": "master",
}
}
components={
Array [
"main.js",
]
}
issue={
Object {
"actions": Array [],

+ 2
- 2
server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewer.tsx View File

@@ -17,9 +17,9 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const CrossComponentSourceViewer = lazyLoad(
const CrossComponentSourceViewer = lazyLoadComponent(
() => import(/* webpackPrefetch: true */ './CrossComponentSourceViewerWrapper'),
'CrossComponentSourceViewer'
);

+ 3
- 3
server/sonar-web/src/main/js/apps/maintenance/routes.tsx View File

@@ -19,12 +19,12 @@
*/
import * as React from 'react';
import { IndexRoute } from 'react-router';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

export const maintenanceRoutes = (
<IndexRoute component={lazyLoad(() => import('./components/MaintenanceAppContainer'))} />
<IndexRoute component={lazyLoadComponent(() => import('./components/MaintenanceAppContainer'))} />
);

export const setupRoutes = (
<IndexRoute component={lazyLoad(() => import('./components/SetupAppContainer'))} />
<IndexRoute component={lazyLoadComponent(() => import('./components/SetupAppContainer'))} />
);

+ 5
- 2
server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx View File

@@ -21,12 +21,15 @@ import tooltipDCE from 'Docs/tooltips/editions/datacenter.md';
import tooltipDE from 'Docs/tooltips/editions/developer.md';
import tooltipEE from 'Docs/tooltips/editions/enterprise.md';
import * as React from 'react';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getEditionUrl } from '../../../helpers/editions';
import { Edition, EditionKey } from '../../../types/editions';

const DocMarkdownBlock = lazyLoad(() => import('../../../components/docs/DocMarkdownBlock'));
const DocMarkdownBlock = lazyLoadComponent(
() => import('../../../components/docs/DocMarkdownBlock'),
'DocMarkdownBlock'
);

interface Props {
currentEdition?: EditionKey;

+ 1
- 1
server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap View File

@@ -4,7 +4,7 @@ exports[`should display the edition 1`] = `
<div
className="boxed-group boxed-group-inner marketplace-edition"
>
<LazyLoader />
<DocMarkdownBlock />
<div
className="marketplace-edition-action spacer-top"
>

+ 2
- 2
server/sonar-web/src/main/js/apps/marketplace/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./AppContainer')) }
indexRoute: { component: lazyLoadComponent(() => import('./AppContainer')) }
}
];


+ 1
- 5
server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx View File

@@ -29,11 +29,7 @@ interface Props {
export default function OrganizationProjects(props: Props) {
return (
<>
<AllProjectsContainer
isFavorite={false}
location={props.location}
organization={props.organization}
/>
<AllProjectsContainer isFavorite={false} organization={props.organization} />
<Suggestions suggestions="organization_projects" />
</>
);

+ 29
- 13
server/sonar-web/src/main/js/apps/organizations/routes.ts View File

@@ -18,18 +18,18 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { RedirectFunction, RouterState } from 'react-router';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import codingRulesRoutes from '../coding-rules/routes';
import qualityGatesRoutes from '../quality-gates/routes';
import qualityProfilesRoutes from '../quality-profiles/routes';
import webhooksRoutes from '../webhooks/routes';

const OrganizationContainer = lazyLoad(() => import('./components/OrganizationContainer'));
const OrganizationContainer = lazyLoadComponent(() => import('./components/OrganizationContainer'));

const routes = [
{
path: ':organizationKey',
component: lazyLoad(() => import('./components/OrganizationPage')),
component: lazyLoadComponent(() => import('./components/OrganizationPage')),
childRoutes: [
{
indexRoute: {
@@ -43,14 +43,22 @@ const routes = [
path: 'projects',
component: OrganizationContainer,
childRoutes: [
{ indexRoute: { component: lazyLoad(() => import('./components/OrganizationProjects')) } }
{
indexRoute: {
component: lazyLoadComponent(() => import('./components/OrganizationProjects'))
}
}
]
},
{
path: 'issues',
component: OrganizationContainer,
childRoutes: [
{ indexRoute: { component: lazyLoad(() => import('../issues/components/AppContainer')) } }
{
indexRoute: {
component: lazyLoadComponent(() => import('../issues/components/AppContainer'))
}
}
]
},
{
@@ -60,7 +68,9 @@ const routes = [
},
{
path: 'members',
component: lazyLoad(() => import('../organizationMembers/OrganizationMembersContainer'))
component: lazyLoadComponent(() =>
import('../organizationMembers/OrganizationMembersContainer')
)
},
{
path: 'quality_profiles',
@@ -72,26 +82,32 @@ const routes = [
childRoutes: qualityGatesRoutes
},
{
component: lazyLoad(() => import('./components/OrganizationAccessContainer')),
component: lazyLoadComponent(() => import('./components/OrganizationAccessContainer')),
childRoutes: [
{ path: 'edit', component: lazyLoad(() => import('./components/OrganizationEdit')) },
{ path: 'groups', component: lazyLoad(() => import('../groups/components/App')) },
{
path: 'edit',
component: lazyLoadComponent(() => import('./components/OrganizationEdit'))
},
{
path: 'groups',
component: lazyLoadComponent(() => import('../groups/components/App'))
},
{
path: 'permissions',
component: lazyLoad(() => import('../permissions/global/components/App'))
component: lazyLoadComponent(() => import('../permissions/global/components/App'))
},
{
path: 'permission_templates',
component: lazyLoad(() => import('../permission-templates/components/App'))
component: lazyLoadComponent(() => import('../permission-templates/components/App'))
},
{
path: 'projects_management',
component: lazyLoad(() => import('../projectsManagement/AppContainer'))
component: lazyLoadComponent(() => import('../projectsManagement/AppContainer'))
},
{ path: 'webhooks', childRoutes: webhooksRoutes },
{
path: 'extension/:pluginKey/:extensionKey',
component: lazyLoad(() =>
component: lazyLoadComponent(() =>
import('../../app/components/extensions/OrganizationPageExtension')
)
}

+ 3
- 3
server/sonar-web/src/main/js/apps/overview/components/App.tsx View File

@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import { Router, withRouter } from '../../../components/hoc/withRouter';
import { isPullRequest } from '../../../helpers/branch-like';
@@ -26,8 +26,8 @@ import { BranchLike } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
import BranchOverview from '../branches/BranchOverview';

const EmptyOverview = lazyLoad(() => import('./EmptyOverview'));
const PullRequestOverview = lazyLoad(() => import('../pullRequests/PullRequestOverview'));
const EmptyOverview = lazyLoadComponent(() => import('./EmptyOverview'));
const PullRequestOverview = lazyLoadComponent(() => import('../pullRequests/PullRequestOverview'));

interface Props {
branchLike?: BranchLike;

+ 16
- 5
server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx View File

@@ -41,15 +41,23 @@ import { IssueType, MeasurementType, PR_METRICS } from '../utils';
import AfterMergeEstimate from './AfterMergeEstimate';
import LargeQualityGateBadge from './LargeQualityGateBadge';

interface Props {
branchLike: PullRequest;
component: T.Component;
interface StateProps {
conditions?: QualityGateStatusCondition[];
fetchBranchStatus: (branchLike: BranchLike, projectKey: string) => Promise<void>;
ignoredConditions?: boolean;
status?: T.Status;
}

interface DispatchProps {
fetchBranchStatus: (branchLike: BranchLike, projectKey: string) => Promise<void>;
}

interface OwnProps {
branchLike: PullRequest;
component: T.Component;
}

type Props = StateProps & DispatchProps & OwnProps;

interface State {
loading: boolean;
measures: T.MeasureEnhanced[];
@@ -244,4 +252,7 @@ const mapStateToProps = (state: Store, { branchLike, component }: Props) => {

const mapDispatchToProps = { fetchBranchStatus: fetchBranchStatus as any };

export default connect(mapStateToProps, mapDispatchToProps)(PullRequestOverview);
export default connect<StateProps, DispatchProps, OwnProps>(
mapStateToProps,
mapDispatchToProps
)(PullRequestOverview);

+ 2
- 2
server/sonar-web/src/main/js/apps/overview/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/permission-templates/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
}
];


+ 3
- 3
server/sonar-web/src/main/js/apps/permissions/routes.ts View File

@@ -17,16 +17,16 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

export const globalPermissionsRoutes = [
{
indexRoute: { component: lazyLoad(() => import('./global/components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./global/components/App')) }
}
];

export const projectPermissionsRoutes = [
{
indexRoute: { component: lazyLoad(() => import('./project/components/AppContainer')) }
indexRoute: { component: lazyLoadComponent(() => import('./project/components/AppContainer')) }
}
];

+ 2
- 2
server/sonar-web/src/main/js/apps/portfolio/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/projectActivity/routes.ts View File

@@ -17,12 +17,12 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: {
component: lazyLoad(() => import('./components/ProjectActivityAppContainer'))
component: lazyLoadComponent(() => import('./components/ProjectActivityAppContainer'))
}
}
];

+ 2
- 2
server/sonar-web/src/main/js/apps/projectBaseline/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/AppContainer')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/AppContainer')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/projectBranches/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/projectQualityGate/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./App')) }
indexRoute: { component: lazyLoadComponent(() => import('./App')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/projectQualityProfiles/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./App')) }
indexRoute: { component: lazyLoadComponent(() => import('./App')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx View File

@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { areThereCustomOrganizations, getCurrentUser, Store } from '../../../store/rootReducer';

const stateToProps = (state: Store) => ({
@@ -26,4 +26,4 @@ const stateToProps = (state: Store) => ({
organizationsEnabled: areThereCustomOrganizations(state)
});

export default connect(stateToProps)(lazyLoad(() => import('./AllProjects')));
export default connect(stateToProps)(lazyLoadComponent(() => import('./AllProjects')));

+ 2
- 14
server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx View File

@@ -108,13 +108,7 @@ export class DefaultPageSelector extends React.PureComponent<Props, State> {

render() {
if (isSonarCloud() && isLoggedIn(this.props.currentUser)) {
return (
<AllProjectsContainer
isFavorite={true}
location={this.props.location}
organization={undefined}
/>
);
return <AllProjectsContainer isFavorite={true} organization={undefined} />;
}

const { shouldBeRedirected, shouldForceSorting } = this.state;
@@ -124,13 +118,7 @@ export class DefaultPageSelector extends React.PureComponent<Props, State> {
shouldBeRedirected !== true &&
shouldForceSorting === undefined
) {
return (
<AllProjectsContainer
isFavorite={false}
location={this.props.location}
organization={undefined}
/>
);
return <AllProjectsContainer isFavorite={false} organization={undefined} />;
}

return null;

+ 2
- 2
server/sonar-web/src/main/js/apps/projects/routes.ts View File

@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { RedirectFunction, RouterState } from 'react-router';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { save } from 'sonar-ui-common/helpers/storage';
import { isDefined } from 'sonar-ui-common/helpers/types';
import DefaultPageSelectorContainer from './components/DefaultPageSelectorContainer';
@@ -37,7 +37,7 @@ const routes = [
{ path: 'favorite', component: FavoriteProjectsContainer },
{
path: 'create',
component: lazyLoad(() => import('../create/project/CreateProjectPage'))
component: lazyLoadComponent(() => import('../create/project/CreateProjectPage'))
}
].filter(isDefined);


+ 2
- 2
server/sonar-web/src/main/js/apps/projectsManagement/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./AppContainer')) }
indexRoute: { component: lazyLoadComponent(() => import('./AppContainer')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/quality-gates/routes.ts View File

@@ -17,9 +17,9 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const App = lazyLoad(() => import('./components/App'));
const App = lazyLoadComponent(() => import('./components/App'));

const routes = [{ indexRoute: { component: App } }, { path: 'show/:id', component: App }];


+ 2
- 2
server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResultActivation.tsx View File

@@ -19,13 +19,13 @@
*/
import * as React from 'react';
import { Button } from 'sonar-ui-common/components/controls/buttons';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { Profile } from '../../../api/quality-profiles';
import { getRuleDetails } from '../../../api/rules';

const ActivationFormModal = lazyLoad(
const ActivationFormModal = lazyLoadComponent(
() => import('../../coding-rules/components/ActivationFormModal'),
'ActivationFormModal'
);

+ 7
- 7
server/sonar-web/src/main/js/apps/quality-profiles/routes.ts View File

@@ -17,27 +17,27 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
component: lazyLoad(() => import('./components/AppContainer')),
indexRoute: { component: lazyLoad(() => import('./home/HomeContainer')) },
component: lazyLoadComponent(() => import('./components/AppContainer')),
indexRoute: { component: lazyLoadComponent(() => import('./home/HomeContainer')) },
childRoutes: [
{
component: lazyLoad(() => import('./components/ProfileContainer')),
component: lazyLoadComponent(() => import('./components/ProfileContainer')),
childRoutes: [
{
path: 'show',
component: lazyLoad(() => import('./details/ProfileDetails'))
component: lazyLoadComponent(() => import('./details/ProfileDetails'))
},
{
path: 'changelog',
component: lazyLoad(() => import('./changelog/ChangelogContainer'))
component: lazyLoadComponent(() => import('./changelog/ChangelogContainer'))
},
{
path: 'compare',
component: lazyLoad(() => import('./compare/ComparisonContainer'))
component: lazyLoadComponent(() => import('./compare/ComparisonContainer'))
}
]
}

+ 5
- 5
server/sonar-web/src/main/js/apps/sessions/routes.ts View File

@@ -17,24 +17,24 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
path: 'new',
component: lazyLoad(() => import('./components/LoginContainer'))
component: lazyLoadComponent(() => import('./components/LoginContainer'))
},
{
path: 'logout',
component: lazyLoad(() => import('./components/Logout'))
component: lazyLoadComponent(() => import('./components/Logout'))
},
{
path: 'unauthorized',
component: lazyLoad(() => import('./components/Unauthorized'))
component: lazyLoadComponent(() => import('./components/Unauthorized'))
},
{
path: 'email_already_exists',
component: lazyLoad(() => import('./components/EmailAlreadyExists'))
component: lazyLoadComponent(() => import('./components/EmailAlreadyExists'))
}
];


+ 3
- 3
server/sonar-web/src/main/js/apps/settings/routes.ts View File

@@ -17,15 +17,15 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/AppContainer')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/AppContainer')) }
},
{
path: 'encryption',
component: lazyLoad(() => import('./encryption/EncryptionApp'))
component: lazyLoadComponent(() => import('./encryption/EncryptionApp'))
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/system/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
}
];


+ 2
- 5
server/sonar-web/src/main/js/apps/tutorials/routes.ts View File

@@ -17,15 +17,12 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { isSonarCloud } from '../../helpers/system';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: {
component: lazyLoad(() =>
isSonarCloud() ? import('./onboarding/OnboardingPage') : import('./ProjectOnboardingPage')
)
component: lazyLoadComponent(() => import('./ProjectOnboardingPage'))
}
}
];

+ 2
- 2
server/sonar-web/src/main/js/apps/users/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./UsersAppContainer')) }
indexRoute: { component: lazyLoadComponent(() => import('./UsersAppContainer')) }
}
];


+ 3
- 3
server/sonar-web/src/main/js/apps/web-api/routes.ts View File

@@ -17,15 +17,15 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/WebApiApp')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/WebApiApp')) }
},
{
path: '**',
component: lazyLoad(() => import('./components/WebApiApp'))
component: lazyLoadComponent(() => import('./components/WebApiApp'))
}
];


+ 2
- 2
server/sonar-web/src/main/js/apps/webhooks/routes.ts View File

@@ -17,11 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const routes = [
{
indexRoute: { component: lazyLoad(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
}
];


+ 2
- 2
server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx View File

@@ -17,9 +17,9 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';

const SourceViewer = lazyLoad(
const SourceViewer = lazyLoadComponent(
() => import(/* webpackPrefetch: true */ './SourceViewerBase'),
'SourceViewer'
);

+ 99
- 103
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx View File

@@ -67,17 +67,17 @@ export interface Props {
// but kept to maintaint the location indexes
highlightedLocations?: (T.FlowLocation | undefined)[];
highlightedLocationMessage?: { index: number; text: string | undefined };
loadComponent: (
loadComponent?: (
component: string,
branchLike: BranchLike | undefined
) => Promise<T.SourceViewerFile>;
loadIssues: (
loadIssues?: (
component: string,
from: number,
to: number,
branchLike: BranchLike | undefined
) => Promise<T.Issue[]>;
loadSources: (
loadSources?: (
component: string,
from: number,
to: number,
@@ -129,10 +129,7 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
displayAllIssues: false,
displayIssueLocationsCount: true,
displayIssueLocationsLink: true,
displayLocationMarkers: true,
loadComponent: defaultLoadComponent,
loadIssues: defaultLoadIssues,
loadSources: defaultLoadSources
displayLocationMarkers: true
};

constructor(props: Props) {
@@ -208,6 +205,18 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
this.mounted = false;
}

get loadComponent() {
return this.props.loadComponent || defaultLoadComponent;
}

get loadIssues() {
return this.props.loadIssues || defaultLoadIssues;
}

get propsLoadSources() {
return this.props.loadSources || defaultLoadSources;
}

computeCoverageStatus(lines: T.SourceLine[]) {
return lines.map(line => ({ ...line, coverageStatus: getCoverageStatus(line) }));
}
@@ -228,7 +237,7 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>

const to = (this.props.aroundLine || 0) + LINES;
const loadIssues = (component: T.SourceViewerFile, sources: T.SourceLine[]) => {
this.props.loadIssues(this.props.component, 1, to, this.props.branchLike).then(
this.loadIssues(this.props.component, 1, to, this.props.branchLike).then(
issues => {
if (this.mounted) {
const finalSources = sources.slice(0, LINES);
@@ -300,9 +309,10 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
);
};

this.props
.loadComponent(this.props.component, this.props.branchLike)
.then(onResolve, onFailLoadComponent);
this.loadComponent(this.props.component, this.props.branchLike).then(
onResolve,
onFailLoadComponent
);
}

fetchSources() {
@@ -335,27 +345,25 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
}
const firstSourceLine = this.state.sources[0];
const lastSourceLine = this.state.sources[this.state.sources.length - 1];
this.props
.loadIssues(
this.props.component,
firstSourceLine && firstSourceLine.line,
lastSourceLine && lastSourceLine.line,
this.props.branchLike
)
.then(
issues => {
if (this.mounted) {
this.setState({
issues,
issuesByLine: issuesByLine(issues),
issueLocationsByLine: locationsByLine(issues)
});
}
},
() => {
// TODO
this.loadIssues(
this.props.component,
firstSourceLine && firstSourceLine.line,
lastSourceLine && lastSourceLine.line,
this.props.branchLike
).then(
issues => {
if (this.mounted) {
this.setState({
issues,
issuesByLine: issuesByLine(issues),
issueLocationsByLine: locationsByLine(issues)
});
}
);
},
() => {
// TODO
}
);
}

loadSources = (): Promise<T.SourceLine[]> => {
@@ -381,9 +389,10 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
// request one additional line to define `hasSourcesAfter`
to++;

return this.props
.loadSources(this.props.component, from, to, this.props.branchLike)
.then(sources => resolve(sources), onFailLoadSources);
return this.propsLoadSources(this.props.component, from, to, this.props.branchLike).then(
sources => resolve(sources),
onFailLoadSources
);
});
};

@@ -394,43 +403,34 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
const firstSourceLine = this.state.sources[0];
this.setState({ loadingSourcesBefore: true });
const from = Math.max(1, firstSourceLine.line - LINES);
this.props
.loadSources(this.props.component, from, firstSourceLine.line - 1, this.props.branchLike)
.then(
sources => {
this.props
.loadIssues(this.props.component, from, firstSourceLine.line - 1, this.props.branchLike)
.then(
issues => {
if (this.mounted) {
this.setState(prevState => {
const nextIssues = uniqBy(
[...issues, ...(prevState.issues || [])],
issue => issue.key
);
return {
issues: nextIssues,
issuesByLine: issuesByLine(nextIssues),
issueLocationsByLine: locationsByLine(nextIssues),
loadingSourcesBefore: false,
sources: [
...this.computeCoverageStatus(sources),
...(prevState.sources || [])
],
symbolsByLine: { ...prevState.symbolsByLine, ...symbolsByLine(sources) }
};
});
}
},
() => {
// TODO
}
);
},
() => {
// TODO
Promise.all([
this.propsLoadSources(
this.props.component,
from,
firstSourceLine.line - 1,
this.props.branchLike
),
this.loadIssues(this.props.component, from, firstSourceLine.line - 1, this.props.branchLike)
]).then(
([sources, issues]) => {
if (this.mounted) {
this.setState(prevState => {
const nextIssues = uniqBy([...issues, ...(prevState.issues || [])], issue => issue.key);
return {
issues: nextIssues,
issuesByLine: issuesByLine(nextIssues),
issueLocationsByLine: locationsByLine(nextIssues),
loadingSourcesBefore: false,
sources: [...this.computeCoverageStatus(sources), ...(prevState.sources || [])],
symbolsByLine: { ...prevState.symbolsByLine, ...symbolsByLine(sources) }
};
});
}
);
},
() => {
// TODO
}
);
};

loadSourcesAfter = () => {
@@ -442,38 +442,31 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
const fromLine = lastSourceLine.line + 1;
// request one additional line to define `hasSourcesAfter`
const toLine = lastSourceLine.line + LINES + 1;
this.props.loadSources(this.props.component, fromLine, toLine, this.props.branchLike).then(
sources => {
this.props.loadIssues(this.props.component, fromLine, toLine, this.props.branchLike).then(
issues => {
if (this.mounted) {
this.setState(prevState => {
const nextIssues = uniqBy(
[...(prevState.issues || []), ...issues],
issue => issue.key
);
return {
issues: nextIssues,
issuesByLine: issuesByLine(nextIssues),
issueLocationsByLine: locationsByLine(nextIssues),
hasSourcesAfter: sources.length > LINES,
loadingSourcesAfter: false,
sources: [
...(prevState.sources || []),
...this.computeCoverageStatus(sources.slice(0, LINES))
],
symbolsByLine: {
...prevState.symbolsByLine,
...symbolsByLine(sources.slice(0, LINES))
}
};
});
}
},
() => {
// TODO
}
);
Promise.all([
this.propsLoadSources(this.props.component, fromLine, toLine, this.props.branchLike),
this.loadIssues(this.props.component, fromLine, toLine, this.props.branchLike)
]).then(
([sources, issues]) => {
if (this.mounted) {
this.setState(prevState => {
const nextIssues = uniqBy([...(prevState.issues || []), ...issues], issue => issue.key);
return {
issues: nextIssues,
issuesByLine: issuesByLine(nextIssues),
issueLocationsByLine: locationsByLine(nextIssues),
hasSourcesAfter: sources.length > LINES,
loadingSourcesAfter: false,
sources: [
...(prevState.sources || []),
...this.computeCoverageStatus(sources.slice(0, LINES))
],
symbolsByLine: {
...prevState.symbolsByLine,
...symbolsByLine(sources.slice(0, LINES))
}
};
});
}
},
() => {
// TODO
@@ -723,7 +716,10 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
}
}

function defaultLoadComponent(component: string, branchLike: BranchLike | undefined) {
function defaultLoadComponent(
component: string,
branchLike: BranchLike | undefined
): Promise<T.SourceViewerFile> {
return Promise.all([
getComponentForSourceViewer({ component, ...getBranchLikeQuery(branchLike) }),
getComponentData({ component, ...getBranchLikeQuery(branchLike) })

+ 127
- 4
server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerBase-test.tsx View File

@@ -17,14 +17,137 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { shallow } from 'enzyme';
import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { getComponentData, getComponentForSourceViewer, getSources } from '../../../api/components';
import { mockMainBranch } from '../../../helpers/mocks/branch-like';
import { mockIssue, mockSourceLine, mockSourceViewerFile } from '../../../helpers/testMocks';
import defaultLoadIssues from '../helpers/loadIssues';
import SourceViewerBase from '../SourceViewerBase';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
jest.mock('../helpers/loadIssues', () => ({
default: jest.fn().mockRejectedValue({})
}));

jest.mock('../../../api/components', () => ({
getComponentForSourceViewer: jest.fn().mockRejectedValue(''),
getComponentData: jest.fn().mockRejectedValue(''),
getSources: jest.fn().mockRejectedValue('')
}));

beforeEach(() => {
jest.resetAllMocks();
});

it('should render nothing from the start', () => {
expect(shallowRender().type()).toBeNull();
});

it('should render correctly', async () => {
(defaultLoadIssues as jest.Mock).mockResolvedValueOnce([mockIssue()]);
(getComponentForSourceViewer as jest.Mock).mockResolvedValueOnce(mockSourceViewerFile());
(getComponentData as jest.Mock).mockResolvedValueOnce({
component: { leakPeriodDate: '2018-06-20T17:12:19+0200' }
});
(getSources as jest.Mock).mockResolvedValueOnce([]);

const wrapper = shallowRender();
await waitAndUpdate(wrapper);

expect(wrapper).toMatchSnapshot();
});

it('should use load props if provided', () => {
const loadComponent = jest.fn().mockResolvedValue({});
const loadIssues = jest.fn().mockResolvedValue([]);
const loadSources = jest.fn().mockResolvedValue([]);
const wrapper = shallowRender({
loadComponent,
loadIssues,
loadSources
});

expect(wrapper.instance().loadComponent).toBe(loadComponent);
});

it('should reload', async () => {
(defaultLoadIssues as jest.Mock)
.mockResolvedValueOnce([mockIssue()])
.mockResolvedValueOnce([mockIssue()]);
(getComponentForSourceViewer as jest.Mock).mockResolvedValueOnce(mockSourceViewerFile());
(getComponentData as jest.Mock).mockResolvedValueOnce({
component: { leakPeriodDate: '2018-06-20T17:12:19+0200' }
});
(getSources as jest.Mock).mockResolvedValueOnce([mockSourceLine()]);

const wrapper = shallowRender();
await waitAndUpdate(wrapper);

wrapper.instance().reloadIssues();

expect(defaultLoadIssues).toBeCalledTimes(2);

await waitAndUpdate(wrapper);

expect(wrapper.state().issues).toHaveLength(1);
});

it('should load sources before', async () => {
(defaultLoadIssues as jest.Mock)
.mockResolvedValueOnce([mockIssue(false, { key: 'issue1' })])
.mockResolvedValueOnce([mockIssue(false, { key: 'issue2' })]);
(getComponentForSourceViewer as jest.Mock).mockResolvedValueOnce(mockSourceViewerFile());
(getComponentData as jest.Mock).mockResolvedValueOnce({
component: { leakPeriodDate: '2018-06-20T17:12:19+0200' }
});
(getSources as jest.Mock)
.mockResolvedValueOnce([mockSourceLine()])
.mockResolvedValueOnce([mockSourceLine()]);

const wrapper = shallowRender();
await waitAndUpdate(wrapper);

wrapper.instance().loadSourcesBefore();
expect(wrapper.state().loadingSourcesBefore).toBe(true);

expect(defaultLoadIssues).toBeCalledTimes(2);
expect(getSources).toBeCalledTimes(2);

await waitAndUpdate(wrapper);
expect(wrapper.state().loadingSourcesBefore).toBe(false);
expect(wrapper.state().issues).toHaveLength(2);
});

it('should load sources after', async () => {
(defaultLoadIssues as jest.Mock)
.mockResolvedValueOnce([mockIssue(false, { key: 'issue1' })])
.mockResolvedValueOnce([mockIssue(false, { key: 'issue2' })]);
(getComponentForSourceViewer as jest.Mock).mockResolvedValueOnce(mockSourceViewerFile());
(getComponentData as jest.Mock).mockResolvedValueOnce({
component: { leakPeriodDate: '2018-06-20T17:12:19+0200' }
});
(getSources as jest.Mock)
.mockResolvedValueOnce([mockSourceLine()])
.mockResolvedValueOnce([mockSourceLine()]);

const wrapper = shallowRender();
await waitAndUpdate(wrapper);

wrapper.instance().loadSourcesAfter();
expect(wrapper.state().loadingSourcesAfter).toBe(true);

expect(defaultLoadIssues).toBeCalledTimes(2);
expect(getSources).toBeCalledTimes(2);

await waitAndUpdate(wrapper);

expect(wrapper.state().loadingSourcesAfter).toBe(false);
expect(wrapper.state().issues).toHaveLength(2);
});

function shallowRender() {
return <SourceViewerBase branchLike={mockMainBranch()} component="my-component" />;
function shallowRender(overrides: Partial<SourceViewerBase['props']> = {}) {
return shallow<SourceViewerBase>(
<SourceViewerBase branchLike={mockMainBranch()} component="my-component" {...overrides} />
);
}

+ 158
- 15
server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerBase-test.tsx.snap View File

@@ -1,22 +1,165 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<SourceViewerBase
branchLike={
<ContextProvider
value={
Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,
"isMain": true,
"name": "master",
"branchLike": Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,
"isMain": true,
"name": "master",
},
"file": Object {
"key": "foo",
"leakPeriodDate": "2018-06-20T17:12:19+0200",
"measures": Object {
"coverage": "85.2",
"duplicationDensity": "1.0",
"issues": "12",
"lines": "56",
},
"path": "foo/bar.ts",
"project": "my-project",
"projectName": "MyProject",
"q": "FIL",
"uuid": "foo-bar",
},
}
}
component="my-component"
displayAllIssues={false}
displayIssueLocationsCount={true}
displayIssueLocationsLink={true}
displayLocationMarkers={true}
loadComponent={[Function]}
loadIssues={[Function]}
loadSources={[Function]}
/>
>
<div
className="source-viewer"
>
<ContextConsumer>
<Component />
</ContextConsumer>
<SourceViewerCode
branchLike={
Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,
"isMain": true,
"name": "master",
}
}
componentKey="my-component"
displayAllIssues={false}
displayIssueLocationsCount={true}
displayIssueLocationsLink={true}
displayLocationMarkers={true}
duplicationsByLine={Object {}}
hasSourcesAfter={false}
hasSourcesBefore={false}
highlightedSymbols={Array []}
issueLocationsByLine={
Object {
"25": Array [
Object {
"from": 0,
"line": 25,
"to": 999999,
},
],
"26": Array [
Object {
"from": 0,
"line": 26,
"to": 15,
},
],
}
}
issues={
Array [
Object {
"actions": Array [],
"component": "main.js",
"componentLongName": "main.js",
"componentQualifier": "FIL",
"componentUuid": "foo1234",
"creationDate": "2017-03-01T09:36:01+0100",
"flows": Array [],
"fromHotspot": false,
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
"severity": "MAJOR",
"status": "OPEN",
"textRange": Object {
"endLine": 26,
"endOffset": 15,
"startLine": 25,
"startOffset": 0,
},
"transitions": Array [],
"type": "BUG",
},
]
}
issuesByLine={
Object {
"26": Array [
Object {
"actions": Array [],
"component": "main.js",
"componentLongName": "main.js",
"componentQualifier": "FIL",
"componentUuid": "foo1234",
"creationDate": "2017-03-01T09:36:01+0100",
"flows": Array [],
"fromHotspot": false,
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
"severity": "MAJOR",
"status": "OPEN",
"textRange": Object {
"endLine": 26,
"endOffset": 15,
"startLine": 25,
"startOffset": 0,
},
"transitions": Array [],
"type": "BUG",
},
],
}
}
loadDuplications={[Function]}
loadSourcesAfter={[Function]}
loadSourcesBefore={[Function]}
loadingSourcesAfter={false}
loadingSourcesBefore={false}
onIssueChange={[Function]}
onIssuePopupToggle={[Function]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
onIssuesClose={[Function]}
onIssuesOpen={[Function]}
onLinePopupToggle={[Function]}
onSymbolClick={[Function]}
openIssuesByLine={Object {}}
renderDuplicationPopup={[Function]}
sources={Array []}
symbolsByLine={Object {}}
/>
</div>
</ContextProvider>
`;

+ 2
- 2
server/sonar-web/src/main/js/components/controls/DateInput.tsx View File

@@ -32,7 +32,7 @@ import Select from 'sonar-ui-common/components/controls/Select';
import CalendarIcon from 'sonar-ui-common/components/icons/CalendarIcon';
import ChevronLeftIcon from 'sonar-ui-common/components/icons/ChevronLeftIcon';
import ChevronRightIcon from 'sonar-ui-common/components/icons/ChevronRightIcon';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import {
getShortMonthName,
getShortWeekDayName,
@@ -41,7 +41,7 @@ import {
import './DayPicker.css';
import './styles.css';

const DayPicker = lazyLoad(() => import('react-day-picker'));
const DayPicker = lazyLoadComponent(() => import('react-day-picker'), 'DayPicker');

interface Props {
className?: string;

+ 2
- 2
server/sonar-web/src/main/js/components/docs/DocTooltip.tsx View File

@@ -19,10 +19,10 @@
*/
import * as React from 'react';
import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { filterContent } from '../../helpers/markdown';

const DocMarkdownBlock = lazyLoad(() => import('./DocMarkdownBlock'));
const DocMarkdownBlock = lazyLoadComponent(() => import('./DocMarkdownBlock'), 'DocMarkdownBlock');

interface Props {
className?: string;

+ 1
- 1
server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap View File

@@ -8,7 +8,7 @@ exports[`should render 2`] = `
<div
className="abs-width-300"
>
<LazyLoader
<DocMarkdownBlock
className="cut-margins"
content="this is *bold* text"
isTooltip={true}

+ 10
- 4
server/sonar-web/src/main/js/components/workspace/Workspace.tsx View File

@@ -19,16 +19,22 @@
*/
import { omit, uniqBy } from 'lodash';
import * as React from 'react';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { get, save } from 'sonar-ui-common/helpers/storage';
import { ComponentDescriptor, RuleDescriptor, WorkspaceContext } from './context';
import './styles.css';
import WorkspacePortal from './WorkspacePortal';

const WORKSPACE = 'sonarqube-workspace';
const WorkspaceNav = lazyLoad(() => import('./WorkspaceNav'));
const WorkspaceRuleViewer = lazyLoad(() => import('./WorkspaceRuleViewer'));
const WorkspaceComponentViewer = lazyLoad(() => import('./WorkspaceComponentViewer'));
const WorkspaceNav = lazyLoadComponent(() => import('./WorkspaceNav'), 'WorkspaceNav');
const WorkspaceRuleViewer = lazyLoadComponent(
() => import('./WorkspaceRuleViewer'),
'WorkspaceRuleViewer'
);
const WorkspaceComponentViewer = lazyLoadComponent(
() => import('./WorkspaceComponentViewer'),
'WorkspaceComponentViewer'
);

interface State {
components: ComponentDescriptor[];

Loading…
Cancel
Save