From 3a34147be1e725f71b8e102ba53b1f5b9bd10b13 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Mon, 21 Nov 2016 10:03:40 +0100 Subject: step towards a single-entry-point js app (#1362) --- .../main/js/app/components/ComponentContainer.js | 40 ++++ .../src/main/js/app/components/NullComponent.js | 22 ++ .../js/app/components/nav/__tests__/nav-test.js | 31 +++ .../src/main/js/app/components/nav/app.js | 91 +++++++ .../app/components/nav/component/RecentHistory.js | 66 ++++++ .../nav/component/component-nav-breadcrumbs.js | 42 ++++ .../nav/component/component-nav-favorite.js | 36 +++ .../components/nav/component/component-nav-menu.js | 262 ++++++++++++++++++++ .../components/nav/component/component-nav-meta.js | 77 ++++++ .../app/components/nav/component/component-nav.js | 87 +++++++ .../js/app/components/nav/dashboard-name-mixin.js | 32 +++ .../components/nav/global/global-nav-branding.js | 46 ++++ .../app/components/nav/global/global-nav-menu.js | 131 ++++++++++ .../app/components/nav/global/global-nav-search.js | 106 +++++++++ .../app/components/nav/global/global-nav-user.js | 69 ++++++ .../js/app/components/nav/global/global-nav.js | 73 ++++++ .../js/app/components/nav/global/search-view.js | 264 +++++++++++++++++++++ .../components/nav/global/shortcuts-help-view.js | 27 +++ .../src/main/js/app/components/nav/links-mixin.js | 40 ++++ .../js/app/components/nav/settings/settings-nav.js | 133 +++++++++++ .../components/nav/templates/nav-search-empty.hbs | 1 + .../components/nav/templates/nav-search-item.hbs | 22 ++ .../js/app/components/nav/templates/nav-search.hbs | 8 + .../nav/templates/nav-shortcuts-help.hbs | 61 +++++ server/sonar-web/src/main/js/app/index.js | 46 +--- .../sonar-web/src/main/js/app/store/rootReducer.js | 206 +++++++++++++++- server/sonar-web/src/main/js/app/styles/index.js | 5 + .../src/main/js/app/utils/configureLocale.js | 30 +++ .../src/main/js/app/utils/exposeLibraries.js | 28 +++ .../src/main/js/app/utils/isCurrentPathKnown.js | 69 ++++++ .../src/main/js/app/utils/startAjaxMonitoring.js | 192 +++++++++++++++ server/sonar-web/src/main/js/app/utils/startApp.js | 69 ++++++ .../src/main/js/app/utils/startReactApp.js | 116 +++++++++ .../src/main/js/apps/background-tasks/app.js | 43 ---- .../components/BackgroundTasksApp.js | 5 +- .../src/main/js/apps/background-tasks/routes.js | 26 ++ server/sonar-web/src/main/js/apps/code/app.js | 44 ---- .../main/js/apps/code/components/ComponentName.js | 6 +- .../src/main/js/apps/code/components/Search.js | 2 +- server/sonar-web/src/main/js/apps/code/routes.js | 26 ++ .../sonar-web/src/main/js/apps/coding-rules/app.js | 99 -------- .../components/CodingRulesAppContainer.js | 31 +++ .../src/main/js/apps/coding-rules/init.js | 94 ++++++++ .../src/main/js/apps/coding-rules/routes.js | 26 ++ .../src/main/js/apps/component-issues/app.js | 116 --------- .../components/ComponentIssuesAppContainer.js | 31 +++ .../src/main/js/apps/component-issues/init.js | 118 +++++++++ .../src/main/js/apps/component-issues/routes.js | 26 ++ .../src/main/js/apps/component-measures/app.js | 81 ------- .../src/main/js/apps/component-measures/app/App.js | 1 + .../js/apps/component-measures/app/AppContainer.js | 9 +- .../main/js/apps/component-measures/app/actions.js | 9 +- .../main/js/apps/component-measures/app/reducer.js | 4 +- .../bubbleChart/MeasureBubbleChartContainer.js | 6 +- .../component-measures/details/MeasureDetails.js | 4 +- .../details/MeasureDetailsContainer.js | 21 +- .../js/apps/component-measures/details/actions.js | 9 +- .../details/drilldown/ListViewContainer.js | 31 ++- .../details/drilldown/MeasureDrilldown.js | 33 ++- .../details/drilldown/TreeViewContainer.js | 48 ++-- .../details/history/MeasureHistoryContainer.js | 6 +- .../details/treemap/MeasureTreemapContainer.js | 6 +- .../home/AllMeasuresContainer.js | 12 +- .../home/DomainMeasuresContainer.js | 12 +- .../main/js/apps/component-measures/home/Home.js | 4 +- .../apps/component-measures/home/HomeContainer.js | 12 +- .../apps/component-measures/home/MeasuresList.js | 2 +- .../js/apps/component-measures/home/actions.js | 8 +- .../src/main/js/apps/component-measures/routes.js | 49 ++++ .../component-measures/store/configureStore.js | 41 ---- .../component-measures/store/listViewActions.js | 11 +- .../apps/component-measures/store/rootReducer.js | 116 +++++++++ .../apps/component-measures/store/statusActions.js | 4 +- .../component-measures/store/treeViewActions.js | 21 +- .../src/main/js/apps/custom-measures/app.js | 68 ------ .../components/CustomMeasuresAppContainer.js | 39 +++ .../src/main/js/apps/custom-measures/init.js | 68 ++++++ .../src/main/js/apps/custom-measures/routes.js | 26 ++ server/sonar-web/src/main/js/apps/groups/app.js | 64 ----- .../apps/groups/components/GroupsAppContainer.js | 31 +++ server/sonar-web/src/main/js/apps/groups/init.js | 64 +++++ server/sonar-web/src/main/js/apps/groups/routes.js | 26 ++ server/sonar-web/src/main/js/apps/issues/app.js | 82 ------- .../apps/issues/components/IssuesAppContainer.js | 31 +++ server/sonar-web/src/main/js/apps/issues/init.js | 82 +++++++ server/sonar-web/src/main/js/apps/issues/routes.js | 26 ++ .../sonar-web/src/main/js/apps/maintenance/app.js | 38 --- .../components/MaintenanceAppContainer.js | 31 +++ .../maintenance/components/SetupAppContainer.js | 31 +++ .../sonar-web/src/main/js/apps/maintenance/init.js | 38 +++ .../src/main/js/apps/maintenance/routes.js | 31 +++ server/sonar-web/src/main/js/apps/markdown/app.js | 31 --- .../main/js/apps/markdown/markdown-help-view.js | 26 -- .../js/apps/markdown/templates/markdown-help.hbs | 100 -------- server/sonar-web/src/main/js/apps/metrics/app.js | 82 ------- .../apps/metrics/components/MetricsAppContainer.js | 31 +++ server/sonar-web/src/main/js/apps/metrics/init.js | 82 +++++++ .../sonar-web/src/main/js/apps/metrics/routes.js | 26 ++ server/sonar-web/src/main/js/apps/overview/app.js | 31 --- .../js/apps/overview/components/AppContainer.js | 43 ++++ .../sonar-web/src/main/js/apps/overview/routes.js | 28 +++ .../src/main/js/apps/permission-templates/app.js | 44 ---- .../permission-templates/components/ActionsCell.js | 2 +- .../components/AppContainer.js | 41 ++++ .../permission-templates/components/NameCell.js | 2 +- .../components/TemplateHeader.js | 2 +- .../main/js/apps/permission-templates/routes.js | 26 ++ .../src/main/js/apps/permissions/global/app.js | 35 --- .../global/components/AllHoldersList.js | 40 ++-- .../permissions/global/components/PageHeader.js | 4 +- .../js/apps/permissions/global/store/actions.js | 49 ++-- .../src/main/js/apps/permissions/project/app.js | 35 --- .../project/components/AllHoldersList.js | 40 ++-- .../js/apps/permissions/project/components/App.js | 10 +- .../permissions/project/components/PageHeader.js | 4 +- .../js/apps/permissions/project/store/actions.js | 49 ++-- .../src/main/js/apps/permissions/routes.js | 31 +++ .../permissions/shared/components/PageError.js | 4 +- .../js/apps/permissions/shared/store/actions.js | 13 +- .../main/js/apps/permissions/shared/store/error.js | 21 +- .../js/apps/permissions/shared/store/filter.js | 4 +- .../apps/permissions/shared/store/groups/byName.js | 7 +- .../apps/permissions/shared/store/groups/names.js | 4 +- .../js/apps/permissions/shared/store/loading.js | 6 +- .../main/js/apps/permissions/shared/store/query.js | 6 +- .../permissions/shared/store/selectedPermission.js | 4 +- .../apps/permissions/shared/store/users/byLogin.js | 7 +- .../apps/permissions/shared/store/users/logins.js | 4 +- .../src/main/js/apps/project-admin/app.js | 66 ------ .../components/GlobalMessagesContainer.js | 4 +- .../js/apps/project-admin/deletion/Deletion.js | 6 +- .../main/js/apps/project-admin/key/BulkUpdate.js | 2 +- .../src/main/js/apps/project-admin/key/Key.js | 6 +- .../src/main/js/apps/project-admin/links/Links.js | 4 +- .../apps/project-admin/quality-gate/QualityGate.js | 6 +- .../quality-profiles/QualityProfiles.js | 6 +- .../src/main/js/apps/project-admin/routes.js | 34 +++ .../main/js/apps/project-admin/store/actions.js | 26 +- .../main/js/apps/projects-admin/AppContainer.js | 55 +++++ .../src/main/js/apps/projects-admin/app.js | 33 --- .../src/main/js/apps/projects-admin/routes.js | 26 ++ .../sonar-web/src/main/js/apps/projects/routes.js | 2 +- .../src/main/js/apps/quality-gates/routes.js | 2 +- .../src/main/js/apps/quality-profiles/routes.js | 2 +- server/sonar-web/src/main/js/apps/settings/app.js | 56 ----- .../apps/settings/components/AllCategoriesList.js | 4 +- .../src/main/js/apps/settings/components/App.js | 4 +- .../js/apps/settings/components/AppContainer.js | 40 ++++ .../js/apps/settings/components/CategoriesList.js | 6 +- .../settings/components/CategoryDefinitionsList.js | 4 +- .../main/js/apps/settings/components/Definition.js | 12 +- .../settings/components/GlobalMessagesContainer.js | 4 +- .../settings/encryption/EncryptionAppContainer.js | 4 +- .../apps/settings/licenses/LicenseRowContainer.js | 4 +- .../settings/licenses/LicensesListContainer.js | 4 +- .../sonar-web/src/main/js/apps/settings/routes.js | 33 +++ .../src/main/js/apps/settings/store/actions.js | 6 +- server/sonar-web/src/main/js/apps/system/app.js | 28 --- server/sonar-web/src/main/js/apps/system/routes.js | 27 +++ .../src/main/js/apps/update-center/app.js | 82 ------- .../components/UpdateCenterAppContainer.js | 31 +++ .../src/main/js/apps/update-center/init.js | 81 +++++++ .../src/main/js/apps/update-center/routes.js | 30 +++ server/sonar-web/src/main/js/apps/users/app.js | 67 ------ .../js/apps/users/components/UsersAppContainer.js | 31 +++ server/sonar-web/src/main/js/apps/users/init.js | 66 ++++++ server/sonar-web/src/main/js/apps/users/routes.js | 26 ++ server/sonar-web/src/main/js/apps/web-api/app.js | 41 ---- .../src/main/js/apps/web-api/components/Action.js | 2 +- .../src/main/js/apps/web-api/components/Menu.js | 2 +- .../main/js/apps/web-api/components/WebApiApp.js | 11 +- .../sonar-web/src/main/js/apps/web-api/routes.js | 27 +++ server/sonar-web/src/main/js/main/app.js | 85 ------- server/sonar-web/src/main/js/main/common-styles.js | 25 -- .../src/main/js/main/nav/__tests__/nav-test.js | 31 --- server/sonar-web/src/main/js/main/nav/app.js | 91 ------- .../main/js/main/nav/component/RecentHistory.js | 66 ------ .../nav/component/component-nav-breadcrumbs.js | 42 ---- .../main/nav/component/component-nav-favorite.js | 36 --- .../js/main/nav/component/component-nav-menu.js | 262 -------------------- .../js/main/nav/component/component-nav-meta.js | 77 ------ .../main/js/main/nav/component/component-nav.js | 87 ------- .../src/main/js/main/nav/dashboard-name-mixin.js | 32 --- .../main/js/main/nav/global/global-nav-branding.js | 46 ---- .../src/main/js/main/nav/global/global-nav-menu.js | 131 ---------- .../main/js/main/nav/global/global-nav-search.js | 106 --------- .../src/main/js/main/nav/global/global-nav-user.js | 69 ------ .../src/main/js/main/nav/global/global-nav.js | 73 ------ .../src/main/js/main/nav/global/search-view.js | 264 --------------------- .../main/js/main/nav/global/shortcuts-help-view.js | 27 --- .../sonar-web/src/main/js/main/nav/links-mixin.js | 40 ---- .../src/main/js/main/nav/settings/settings-nav.js | 133 ----------- .../js/main/nav/templates/nav-search-empty.hbs | 1 - .../main/js/main/nav/templates/nav-search-item.hbs | 22 -- .../src/main/js/main/nav/templates/nav-search.hbs | 8 - .../js/main/nav/templates/nav-shortcuts-help.hbs | 61 ----- server/sonar-web/src/main/js/main/processes.js | 190 --------------- .../webapp/WEB-INF/app/views/about/index.html.erb | 1 - .../WEB-INF/app/views/account/index.html.erb | 1 - .../app/views/background_tasks/index.html.erb | 3 - .../webapp/WEB-INF/app/views/code/index.html.erb | 3 - .../WEB-INF/app/views/coding_rules/index.html.erb | 3 - .../app/views/component_issues/index.html.erb | 1 - .../app/views/component_measures/index.html.erb | 3 - .../app/views/custom_measures/index.html.erb | 1 - .../WEB-INF/app/views/dashboard/overview.html.erb | 1 - .../webapp/WEB-INF/app/views/groups/index.html.erb | 3 - .../webapp/WEB-INF/app/views/issues/index.html.erb | 3 - .../WEB-INF/app/views/layouts/_footer.html.erb | 2 +- .../WEB-INF/app/views/layouts/nonav.html.erb | 2 +- .../WEB-INF/app/views/maintenance/index.html.erb | 7 - .../WEB-INF/app/views/markdown/help.html.erb | 110 ++++++++- .../WEB-INF/app/views/metrics/index.html.erb | 3 - .../app/views/permission_templates/index.html.erb | 3 - .../WEB-INF/app/views/profiles/index.html.erb | 3 - .../app/views/project/background_tasks.html.erb | 6 - .../WEB-INF/app/views/project/deletion.html.erb | 3 - .../webapp/WEB-INF/app/views/project/key.html.erb | 3 - .../WEB-INF/app/views/project/links.html.erb | 3 - .../app/views/project/quality_gate.html.erb | 3 - .../app/views/project/quality_profiles.html.erb | 3 - .../WEB-INF/app/views/project/settings.html.erb | 3 - .../WEB-INF/app/views/project_roles/index.html.erb | 3 - .../WEB-INF/app/views/projects/index.html.erb | 3 - .../app/views/projects_admin/index.html.erb | 3 - .../WEB-INF/app/views/quality_gates/index.html.erb | 3 - .../webapp/WEB-INF/app/views/roles/global.html.erb | 3 - .../WEB-INF/app/views/settings/index.html.erb | 3 - .../webapp/WEB-INF/app/views/setup/index.html.erb | 7 - .../webapp/WEB-INF/app/views/system/index.html.erb | 4 - .../WEB-INF/app/views/updatecenter/index.html.erb | 7 - .../webapp/WEB-INF/app/views/users/index.html.erb | 3 - .../WEB-INF/app/views/web_api/index.html.erb | 6 - 233 files changed, 4891 insertions(+), 3880 deletions(-) create mode 100644 server/sonar-web/src/main/js/app/components/ComponentContainer.js create mode 100644 server/sonar-web/src/main/js/app/components/NullComponent.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/__tests__/nav-test.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/app.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/component/RecentHistory.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/component/component-nav-breadcrumbs.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/component/component-nav-favorite.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/component/component-nav-menu.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/component/component-nav-meta.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/component/component-nav.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/dashboard-name-mixin.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/global/global-nav-branding.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/global/global-nav-menu.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/global/global-nav-search.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/global/global-nav-user.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/global/global-nav.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/global/search-view.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/global/shortcuts-help-view.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/links-mixin.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/settings/settings-nav.js create mode 100644 server/sonar-web/src/main/js/app/components/nav/templates/nav-search-empty.hbs create mode 100644 server/sonar-web/src/main/js/app/components/nav/templates/nav-search-item.hbs create mode 100644 server/sonar-web/src/main/js/app/components/nav/templates/nav-search.hbs create mode 100644 server/sonar-web/src/main/js/app/components/nav/templates/nav-shortcuts-help.hbs create mode 100644 server/sonar-web/src/main/js/app/utils/configureLocale.js create mode 100644 server/sonar-web/src/main/js/app/utils/exposeLibraries.js create mode 100644 server/sonar-web/src/main/js/app/utils/isCurrentPathKnown.js create mode 100644 server/sonar-web/src/main/js/app/utils/startAjaxMonitoring.js create mode 100644 server/sonar-web/src/main/js/app/utils/startApp.js create mode 100644 server/sonar-web/src/main/js/app/utils/startReactApp.js delete mode 100644 server/sonar-web/src/main/js/apps/background-tasks/app.js create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/code/app.js create mode 100644 server/sonar-web/src/main/js/apps/code/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/coding-rules/app.js create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/init.js create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/component-issues/app.js create mode 100644 server/sonar-web/src/main/js/apps/component-issues/components/ComponentIssuesAppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/component-issues/init.js create mode 100644 server/sonar-web/src/main/js/apps/component-issues/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/app.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/store/configureStore.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/store/rootReducer.js delete mode 100644 server/sonar-web/src/main/js/apps/custom-measures/app.js create mode 100644 server/sonar-web/src/main/js/apps/custom-measures/components/CustomMeasuresAppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/custom-measures/init.js create mode 100644 server/sonar-web/src/main/js/apps/custom-measures/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/groups/app.js create mode 100644 server/sonar-web/src/main/js/apps/groups/components/GroupsAppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/groups/init.js create mode 100644 server/sonar-web/src/main/js/apps/groups/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/issues/app.js create mode 100644 server/sonar-web/src/main/js/apps/issues/components/IssuesAppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/issues/init.js create mode 100644 server/sonar-web/src/main/js/apps/issues/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/maintenance/app.js create mode 100644 server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/maintenance/init.js create mode 100644 server/sonar-web/src/main/js/apps/maintenance/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/markdown/app.js delete mode 100644 server/sonar-web/src/main/js/apps/markdown/markdown-help-view.js delete mode 100644 server/sonar-web/src/main/js/apps/markdown/templates/markdown-help.hbs delete mode 100644 server/sonar-web/src/main/js/apps/metrics/app.js create mode 100644 server/sonar-web/src/main/js/apps/metrics/components/MetricsAppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/metrics/init.js create mode 100644 server/sonar-web/src/main/js/apps/metrics/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/overview/app.js create mode 100644 server/sonar-web/src/main/js/apps/overview/components/AppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/overview/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/permission-templates/app.js create mode 100644 server/sonar-web/src/main/js/apps/permission-templates/components/AppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/permission-templates/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/permissions/global/app.js delete mode 100644 server/sonar-web/src/main/js/apps/permissions/project/app.js create mode 100644 server/sonar-web/src/main/js/apps/permissions/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/project-admin/app.js create mode 100644 server/sonar-web/src/main/js/apps/project-admin/routes.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js delete mode 100644 server/sonar-web/src/main/js/apps/projects-admin/app.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/settings/app.js create mode 100644 server/sonar-web/src/main/js/apps/settings/components/AppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/settings/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/system/app.js create mode 100644 server/sonar-web/src/main/js/apps/system/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/update-center/app.js create mode 100644 server/sonar-web/src/main/js/apps/update-center/components/UpdateCenterAppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/update-center/init.js create mode 100644 server/sonar-web/src/main/js/apps/update-center/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/users/app.js create mode 100644 server/sonar-web/src/main/js/apps/users/components/UsersAppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/users/init.js create mode 100644 server/sonar-web/src/main/js/apps/users/routes.js delete mode 100644 server/sonar-web/src/main/js/apps/web-api/app.js create mode 100644 server/sonar-web/src/main/js/apps/web-api/routes.js delete mode 100644 server/sonar-web/src/main/js/main/app.js delete mode 100644 server/sonar-web/src/main/js/main/common-styles.js delete mode 100644 server/sonar-web/src/main/js/main/nav/__tests__/nav-test.js delete mode 100644 server/sonar-web/src/main/js/main/nav/app.js delete mode 100644 server/sonar-web/src/main/js/main/nav/component/RecentHistory.js delete mode 100644 server/sonar-web/src/main/js/main/nav/component/component-nav-breadcrumbs.js delete mode 100644 server/sonar-web/src/main/js/main/nav/component/component-nav-favorite.js delete mode 100644 server/sonar-web/src/main/js/main/nav/component/component-nav-menu.js delete mode 100644 server/sonar-web/src/main/js/main/nav/component/component-nav-meta.js delete mode 100644 server/sonar-web/src/main/js/main/nav/component/component-nav.js delete mode 100644 server/sonar-web/src/main/js/main/nav/dashboard-name-mixin.js delete mode 100644 server/sonar-web/src/main/js/main/nav/global/global-nav-branding.js delete mode 100644 server/sonar-web/src/main/js/main/nav/global/global-nav-menu.js delete mode 100644 server/sonar-web/src/main/js/main/nav/global/global-nav-search.js delete mode 100644 server/sonar-web/src/main/js/main/nav/global/global-nav-user.js delete mode 100644 server/sonar-web/src/main/js/main/nav/global/global-nav.js delete mode 100644 server/sonar-web/src/main/js/main/nav/global/search-view.js delete mode 100644 server/sonar-web/src/main/js/main/nav/global/shortcuts-help-view.js delete mode 100644 server/sonar-web/src/main/js/main/nav/links-mixin.js delete mode 100644 server/sonar-web/src/main/js/main/nav/settings/settings-nav.js delete mode 100644 server/sonar-web/src/main/js/main/nav/templates/nav-search-empty.hbs delete mode 100644 server/sonar-web/src/main/js/main/nav/templates/nav-search-item.hbs delete mode 100644 server/sonar-web/src/main/js/main/nav/templates/nav-search.hbs delete mode 100644 server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs delete mode 100644 server/sonar-web/src/main/js/main/processes.js (limited to 'server/sonar-web/src/main') diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainer.js b/server/sonar-web/src/main/js/app/components/ComponentContainer.js new file mode 100644 index 00000000000..f31850c3122 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/ComponentContainer.js @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; + +export default class ComponentContainer extends React.Component { + state = {}; + + componentDidMount () { + window.sonarqube.appStarted.then(options => { + this.setState({ component: options.component }); + }); + } + + render () { + if (!this.state.component) { + return null; + } + + return React.cloneElement(this.props.children, { + component: this.state.component + }); + } +} diff --git a/server/sonar-web/src/main/js/app/components/NullComponent.js b/server/sonar-web/src/main/js/app/components/NullComponent.js new file mode 100644 index 00000000000..a3501dfbd16 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/NullComponent.js @@ -0,0 +1,22 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +export default function () { + return null; +} diff --git a/server/sonar-web/src/main/js/app/components/nav/__tests__/nav-test.js b/server/sonar-web/src/main/js/app/components/nav/__tests__/nav-test.js new file mode 100644 index 00000000000..d5ddbab8afd --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/__tests__/nav-test.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { shallow } from 'enzyme'; +import ComponentNavBreadcrumbs from '../component/component-nav-breadcrumbs'; + +describe('ComponentNavBreadcrumbs', () => { + it('should not render breadcrumbs with one element', function () { + const breadcrumbs = [{ key: 'my-project', name: 'My Project', qualifier: 'TRK' }]; + const result = shallow(); + expect(result.find('li').length).toBe(1); + expect(result.find('a').length).toBe(1); + }); +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/app.js b/server/sonar-web/src/main/js/app/components/nav/app.js new file mode 100644 index 00000000000..629c686c071 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/app.js @@ -0,0 +1,91 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 _ from 'underscore'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +import GlobalNav from './global/global-nav'; +import ComponentNav from './component/component-nav'; +import SettingsNav from './settings/settings-nav'; +import { getGlobalNavigation, getComponentNavigation, getSettingsNavigation } from '../../../api/nav'; + +export default class App { + start () { + const options = window.sonarqube; + + require('../../../components/workspace/main'); + + return new Promise((resolve) => { + const response = {}; + const requests = []; + + requests.push( + App.renderGlobalNav(options).then(r => response.global = r) + ); + + if (options.space === 'component') { + requests.push( + App.renderComponentNav(options).then(r => response.component = r) + ); + } else if (options.space === 'settings') { + requests.push( + App.renderSettingsNav(options).then(r => response.settings = r) + ); + } + + Promise.all(requests).then(() => resolve(response)); + }); + } + + static renderGlobalNav (options) { + return getGlobalNavigation().then(r => { + const el = document.getElementById('global-navigation'); + if (el) { + ReactDOM.render(, el); + } + return r; + }); + } + + static renderComponentNav (options) { + return getComponentNavigation(options.componentKey).then(component => { + const el = document.getElementById('context-navigation'); + const nextComponent = { + ...component, + qualifier: _.last(component.breadcrumbs).qualifier + }; + if (el) { + ReactDOM.render(, el); + } + return component; + }); + } + + static renderSettingsNav (options) { + return getSettingsNavigation().then(r => { + const el = document.getElementById('context-navigation'); + const opts = _.extend(r, options); + if (el) { + ReactDOM.render(, el); + } + return r; + }); + } +} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/RecentHistory.js b/server/sonar-web/src/main/js/app/components/nav/component/RecentHistory.js new file mode 100644 index 00000000000..6454cfe8afb --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/component/RecentHistory.js @@ -0,0 +1,66 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 _ from 'underscore'; + +const STORAGE_KEY = 'sonar_recent_history'; +const HISTORY_LIMIT = 10; + +export default class RecentHistory { + static get () { + let history = localStorage.getItem(STORAGE_KEY); + if (history == null) { + history = []; + } else { + try { + history = JSON.parse(history); + } catch (e) { + RecentHistory.clear(); + history = []; + } + } + return history; + } + + static set (newHistory) { + localStorage.setItem(STORAGE_KEY, JSON.stringify(newHistory)); + } + + static clear () { + localStorage.removeItem(STORAGE_KEY); + } + + static add (componentKey, componentName, icon) { + const sonarHistory = RecentHistory.get(); + + if (componentKey) { + const newEntry = { key: componentKey, name: componentName, icon }; + let newHistory = _.reject(sonarHistory, entry => entry.key === newEntry.key); + newHistory.unshift(newEntry); + newHistory = _.first(newHistory, HISTORY_LIMIT); + RecentHistory.set(newHistory); + } + } + + static remove (componentKey) { + const history = RecentHistory.get(); + const newHistory = _.reject(history, entry => entry.key === componentKey); + RecentHistory.set(newHistory); + } +} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/component-nav-breadcrumbs.js b/server/sonar-web/src/main/js/app/components/nav/component/component-nav-breadcrumbs.js new file mode 100644 index 00000000000..7458095814c --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/component/component-nav-breadcrumbs.js @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import QualifierIcon from '../../../../components/shared/qualifier-icon'; + +export default React.createClass({ + render() { + if (!this.props.breadcrumbs) { + return null; + } + const items = this.props.breadcrumbs.map((item, index) => { + const url = `${window.baseUrl}/dashboard/index?id=${encodeURIComponent(item.key)}`; + return ( +
  • + +  {item.name} + +
  • + ); + }); + return ( +
      {items}
    + ); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/component-nav-favorite.js b/server/sonar-web/src/main/js/app/components/nav/component/component-nav-favorite.js new file mode 100644 index 00000000000..72b590e48fb --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/component/component-nav-favorite.js @@ -0,0 +1,36 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import Favorite from '../../../../components/controls/Favorite'; + +export default React.createClass({ + render() { + if (!this.props.canBeFavorite) { + return null; + } + return ( +
    + +
    + ); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/component-nav-menu.js b/server/sonar-web/src/main/js/app/components/nav/component/component-nav-menu.js new file mode 100644 index 00000000000..3321670d281 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/component/component-nav-menu.js @@ -0,0 +1,262 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 qs from 'querystring'; +import classNames from 'classnames'; +import React from 'react'; +import LinksMixin from '../links-mixin'; +import { translate } from '../../../../helpers/l10n'; +import { getComponentUrl } from '../../../../helpers/urls'; + +const SETTINGS_URLS = [ + '/project/settings', + '/project/quality_profiles', + '/project/quality_gate', + '/custom_measures', + '/project/links', + '/project_roles', + '/project/history', + 'background_tasks', + '/project/key', + '/project/deletion' +]; + +export default React.createClass({ + mixins: [LinksMixin], + + isDeveloper() { + return this.props.component.qualifier === 'DEV'; + }, + + isView() { + const { qualifier } = this.props.component; + return qualifier === 'VW' || qualifier === 'SVW'; + }, + + periodParameter() { + const params = qs.parse(window.location.search.substr(1)); + return params.period ? `&period=${params.period}` : ''; + }, + + getPeriod() { + const params = qs.parse(window.location.search.substr(1)); + return params.period; + }, + + isFixedDashboardActive() { + const path = window.location.pathname; + return path.indexOf(window.baseUrl + '/dashboard') === 0 || path.indexOf(window.baseUrl + '/governance') === 0; + }, + + renderDashboardLink() { + const url = getComponentUrl(this.props.component.key); + const name = ; + const className = classNames({ active: this.isFixedDashboardActive() }); + return ( +
  • + {name} +
  • + ); + }, + + renderCodeLink() { + if (this.isDeveloper()) { + return null; + } + + const url = `/code/?id=${encodeURIComponent(this.props.component.key)}`; + const header = this.isView() ? translate('view_projects.page') : translate('code.page'); + return this.renderLink(url, header, '/code'); + }, + + renderComponentIssuesLink() { + const url = `/component_issues?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('issues.page'), '/component_issues'); + }, + + renderComponentMeasuresLink() { + const url = `/component_measures/?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('layout.measures'), '/component_measures'); + }, + + renderAdministration() { + const shouldShowAdministration = + this.props.conf.showBackgroundTasks || + this.props.conf.showHistory || + this.props.conf.showLinks || + this.props.conf.showManualMeasures || + this.props.conf.showPermissions || + this.props.conf.showQualityGates || + this.props.conf.showQualityProfiles || + this.props.conf.showSettings || + this.props.conf.showUpdateKey; + if (!shouldShowAdministration) { + return null; + } + const isSettingsActive = SETTINGS_URLS.some(url => { + return window.location.href.indexOf(url) !== -1; + }); + const className = 'dropdown' + (isSettingsActive ? ' active' : ''); + return ( +
  • + + {translate('layout.settings')}  + + +
      + {this.renderSettingsLink()} + {this.renderProfilesLink()} + {this.renderQualityGateLink()} + {this.renderCustomMeasuresLink()} + {this.renderLinksLink()} + {this.renderPermissionsLink()} + {this.renderHistoryLink()} + {this.renderBackgroundTasksLink()} + {this.renderUpdateKeyLink()} + {this.renderExtensions()} + {this.renderDeletionLink()} +
    +
  • + ); + }, + + renderSettingsLink() { + if (!this.props.conf.showSettings) { + return null; + } + const url = `/project/settings?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('project_settings.page'), '/project/settings'); + }, + + renderProfilesLink() { + if (!this.props.conf.showQualityProfiles) { + return null; + } + const url = `/project/quality_profiles?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('project_quality_profiles.page'), '/project/quality_profiles'); + }, + + renderQualityGateLink() { + if (!this.props.conf.showQualityGates) { + return null; + } + const url = `/project/quality_gate?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('project_quality_gate.page'), '/project/quality_gate'); + }, + + renderCustomMeasuresLink() { + if (!this.props.conf.showManualMeasures) { + return null; + } + const url = `/custom_measures?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('custom_measures.page'), '/custom_measures'); + }, + + renderLinksLink() { + if (!this.props.conf.showLinks) { + return null; + } + const url = `/project/links?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('project_links.page'), '/project/links'); + }, + + renderPermissionsLink() { + if (!this.props.conf.showPermissions) { + return null; + } + const url = `/project_roles?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('permissions.page'), '/project_roles'); + }, + + renderHistoryLink() { + if (!this.props.conf.showHistory) { + return null; + } + const url = `/project/history?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('project_history.page'), '/project/history'); + }, + + renderBackgroundTasksLink() { + if (!this.props.conf.showBackgroundTasks) { + return null; + } + const url = `/project/background_tasks?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('background_tasks.page'), '/project/background_tasks'); + }, + + renderUpdateKeyLink() { + if (!this.props.conf.showUpdateKey) { + return null; + } + const url = `/project/key?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('update_key.page'), '/project/key'); + }, + + renderDeletionLink() { + const { qualifier } = this.props.component; + + if (qualifier !== 'TRK' && qualifier !== 'VW') { + return null; + } + + const url = `/project/deletion?id=${encodeURIComponent(this.props.component.key)}`; + return this.renderLink(url, translate('deletion.page'), '/project/deletion'); + }, + + renderExtensions() { + const extensions = this.props.conf.extensions || []; + return extensions.map(e => this.renderLink(e.url, e.name, e.url)); + }, + + renderTools() { + const extensions = this.props.component.extensions || []; + const withoutGovernance = extensions.filter(ext => ext.name !== 'Governance'); + const tools = withoutGovernance + .map(extension => this.renderLink(extension.url, extension.name)); + + if (!tools.length) { + return null; + } + + return ( +
  • + + {translate('more')}  + + +
      + {tools} +
    +
  • + ); + }, + + render() { + return ( +
      + {this.renderDashboardLink()} + {this.renderComponentIssuesLink()} + {this.renderComponentMeasuresLink()} + {this.renderCodeLink()} + {this.renderTools()} + {this.renderAdministration()} +
    + ); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/component-nav-meta.js b/server/sonar-web/src/main/js/app/components/nav/component/component-nav-meta.js new file mode 100644 index 00000000000..393564cd8a3 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/component/component-nav-meta.js @@ -0,0 +1,77 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 moment from 'moment'; +import React from 'react'; +import PendingIcon from '../../../../components/shared/pending-icon'; +import { translate, translateWithParameters } from '../../../../helpers/l10n'; + +export default React.createClass({ + render() { + const metaList = []; + const canSeeBackgroundTasks = this.props.conf.showBackgroundTasks; + const backgroundTasksUrl = + `${window.baseUrl}/project/background_tasks?id=${encodeURIComponent(this.props.component.key)}`; + + if (this.props.isInProgress) { + const tooltip = canSeeBackgroundTasks ? + translateWithParameters('component_navigation.status.in_progress.admin', backgroundTasksUrl) : + translate('component_navigation.status.in_progress'); + metaList.push( +
  • + + {' '} + {translate('background_task.status.IN_PROGRESS')} +
  • + ); + } else if (this.props.isPending) { + const tooltip = canSeeBackgroundTasks ? + translateWithParameters('component_navigation.status.pending.admin', backgroundTasksUrl) : + translate('component_navigation.status.pending'); + metaList.push( +
  • + {translate('background_task.status.PENDING')} +
  • + ); + } else if (this.props.isFailed) { + const tooltip = canSeeBackgroundTasks ? + translateWithParameters('component_navigation.status.failed.admin', backgroundTasksUrl) : + translate('component_navigation.status.failed'); + metaList.push( +
  • + {translate('background_task.status.FAILED')} +
  • + ); + } + + if (this.props.snapshotDate) { + metaList.push(
  • {moment(this.props.snapshotDate).format('LLL')}
  • ); + } + + if (this.props.version) { + metaList.push(
  • Version {this.props.version}
  • ); + } + + return ( +
    +
      {metaList}
    +
    + ); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/component-nav.js b/server/sonar-web/src/main/js/app/components/nav/component/component-nav.js new file mode 100644 index 00000000000..bb511a169a5 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/component/component-nav.js @@ -0,0 +1,87 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 $ from 'jquery'; +import _ from 'underscore'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { STATUSES } from '../../../../apps/background-tasks/constants'; +import { getTasksForComponent } from '../../../../api/ce'; +import ComponentNavFavorite from './component-nav-favorite'; +import ComponentNavBreadcrumbs from './component-nav-breadcrumbs'; +import ComponentNavMeta from './component-nav-meta'; +import ComponentNavMenu from './component-nav-menu'; +import RecentHistory from './RecentHistory'; + +export default React.createClass({ + componentDidMount() { + this.loadStatus(); + this.populateRecentHistory(); + }, + + loadStatus() { + getTasksForComponent(this.props.component.uuid).then(r => { + this.setState({ + isPending: !!_.findWhere(r.queue, { status: STATUSES.PENDING }), + isInProgress: !!_.findWhere(r.queue, { status: STATUSES.IN_PROGRESS }), + isFailed: r.current && r.current.status === STATUSES.FAILED + }, this.initTooltips); + }); + }, + + populateRecentHistory() { + const qualifier = _.last(this.props.component.breadcrumbs).qualifier; + if (['TRK', 'VW', 'DEV'].indexOf(qualifier) !== -1) { + RecentHistory.add(this.props.component.key, this.props.component.name, qualifier.toLowerCase()); + } + }, + + initTooltips() { + $('[data-toggle="tooltip"]', ReactDOM.findDOMNode(this)).tooltip({ + container: 'body', + placement: 'bottom', + delay: { show: 0, hide: 2000 }, + html: true + }); + }, + + render() { + return ( +
    + + + + + + + +
    + ); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/dashboard-name-mixin.js b/server/sonar-web/src/main/js/app/components/nav/dashboard-name-mixin.js new file mode 100644 index 00000000000..2bc0227b02a --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/dashboard-name-mixin.js @@ -0,0 +1,32 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 { translate } from '../../../helpers/l10n'; + +export default { + getLocalizedDashboardName(baseName) { + const l10nKey = `dashboard.${baseName}.name`; + const l10nLabel = translate(l10nKey); + if (l10nLabel !== l10nKey) { + return l10nLabel; + } else { + return baseName; + } + } +}; diff --git a/server/sonar-web/src/main/js/app/components/nav/global/global-nav-branding.js b/server/sonar-web/src/main/js/app/components/nav/global/global-nav-branding.js new file mode 100644 index 00000000000..6241f7a4b63 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/global/global-nav-branding.js @@ -0,0 +1,46 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { translate } from '../../../../helpers/l10n'; + +export default React.createClass({ + renderLogo() { + const url = this.props.logoUrl || `${window.baseUrl}/images/logo.svg`; + const width = this.props.logoWidth || 100; + const height = 30; + const title = translate('layout.sonar.slogan'); + return {title}; + }, + + render() { + const homeController = window.SS.user ? '/projects/favorite' : '/about'; + const homeUrl = window.baseUrl + homeController; + const homeLinkClassName = 'navbar-brand' + (this.props.logoUrl ? ' navbar-brand-custom' : ''); + return ( + + ); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/global-nav-menu.js b/server/sonar-web/src/main/js/app/components/nav/global/global-nav-menu.js new file mode 100644 index 00000000000..6295431ffb1 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/global/global-nav-menu.js @@ -0,0 +1,131 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import DashboardNameMixin from '../dashboard-name-mixin'; +import LinksMixin from '../links-mixin'; +import { translate } from '../../../../helpers/l10n'; + +export default React.createClass({ + mixins: [DashboardNameMixin, LinksMixin], + + getDefaultProps () { + return { globalDashboards: [], globalPages: [] }; + }, + + renderProjects () { + const controller = window.SS.user ? '/projects/favorite' : '/projects'; + const url = window.baseUrl + controller; + return ( +
  • + {translate('projects.page')} +
  • + ); + }, + + renderIssuesLink () { + const query = window.SS.user ? '#resolved=false|assigned_to_me=true' : '#resolved=false'; + const url = window.baseUrl + '/issues' + query; + return ( +
  • + {translate('issues.page')} +
  • + ); + }, + + renderRulesLink () { + const url = window.baseUrl + '/coding_rules'; + return ( +
  • + {translate('coding_rules.page')} +
  • + ); + }, + + renderProfilesLink() { + const url = window.baseUrl + '/profiles'; + return ( +
  • + {translate('quality_profiles.page')} +
  • + ); + }, + + renderQualityGatesLink () { + const url = window.baseUrl + '/quality_gates'; + return ( +
  • + {translate('quality_gates.page')} +
  • + ); + }, + + renderAdministrationLink () { + if (!window.SS.isUserAdmin) { + return null; + } + const url = window.baseUrl + '/settings'; + return ( +
  • + {translate('layout.settings')} +
  • + ); + }, + + renderGlobalPageLink (globalPage, index) { + const url = window.baseUrl + globalPage.url; + return ( +
  • + {globalPage.name} +
  • + ); + }, + + renderMore () { + if (this.props.globalPages.length === 0) { + return null; + } + const globalPages = this.props.globalPages.map(this.renderGlobalPageLink); + return ( +
  • + + {translate('more')}  + + +
      + {globalPages} +
    +
  • + ); + }, + + render () { + return ( +
      + {this.renderProjects()} + {this.renderIssuesLink()} + {this.renderRulesLink()} + {this.renderProfilesLink()} + {this.renderQualityGatesLink()} + {this.renderAdministrationLink()} + {this.renderMore()} +
    + ); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/global-nav-search.js b/server/sonar-web/src/main/js/app/components/nav/global/global-nav-search.js new file mode 100644 index 00000000000..e84850bf365 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/global/global-nav-search.js @@ -0,0 +1,106 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 Backbone from 'backbone'; +import React from 'react'; +import SearchView from './search-view'; + +function contains (root, node) { + while (node) { + if (node === root) { + return true; + } + node = node.parentNode; + } + return false; +} + +export default React.createClass({ + getInitialState() { + return { open: false }; + }, + + componentDidMount() { + key('s', () => { + const isModalOpen = document.querySelector('html').classList.contains('modal-open'); + if (!isModalOpen) { + this.openSearch(); + } + return false; + }); + }, + + componentWillUnmount() { + this.closeSearch(); + key.unbind('s'); + }, + + openSearch() { + document.addEventListener('click', this.onClickOutside); + this.setState({ open: true }, this.renderSearchView); + }, + + closeSearch() { + document.removeEventListener('click', this.onClickOutside); + this.resetSearchView(); + this.setState({ open: false }); + }, + + renderSearchView() { + const searchContainer = this.refs.container; + this.searchView = new SearchView({ + model: new Backbone.Model(this.props), + hide: this.closeSearch + }); + this.searchView.render().$el.appendTo(searchContainer); + }, + + resetSearchView() { + if (this.searchView) { + this.searchView.destroy(); + } + }, + + onClick(e) { + e.preventDefault(); + if (this.state.open) { + this.closeSearch(); + } else { + this.openSearch(); + } + }, + + onClickOutside(e) { + if (!contains(this.refs.dropdown, e.target)) { + this.closeSearch(); + } + }, + + render() { + const dropdownClassName = 'dropdown' + (this.state.open ? ' open' : ''); + return ( +
  • + +   + +
    +
  • + ); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/global-nav-user.js b/server/sonar-web/src/main/js/app/components/nav/global/global-nav-user.js new file mode 100644 index 00000000000..8c2d0cc9949 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/global/global-nav-user.js @@ -0,0 +1,69 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import Avatar from '../../../../components/ui/Avatar'; +import RecentHistory from '../component/RecentHistory'; +import { translate } from '../../../../helpers/l10n'; + +export default React.createClass({ + renderAuthenticated() { + return ( +
  • + +   + {window.SS.userName}  + + +
  • + ); + }, + + renderAnonymous() { + return ( +
  • + {translate('layout.login')} +
  • + ); + }, + + handleLogin(e) { + e.preventDefault(); + const returnTo = window.location.pathname + window.location.search; + window.location = `${window.baseUrl}/sessions/new?return_to=${encodeURIComponent(returnTo)}${window.location.hash}`; + }, + + handleLogout(e) { + e.preventDefault(); + RecentHistory.clear(); + window.location = `${window.baseUrl}/sessions/logout`; + }, + + render() { + const isUserAuthenticated = !!window.SS.user; + return isUserAuthenticated ? this.renderAuthenticated() : this.renderAnonymous(); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/global-nav.js b/server/sonar-web/src/main/js/app/components/nav/global/global-nav.js new file mode 100644 index 00000000000..1c2916c56de --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/global/global-nav.js @@ -0,0 +1,73 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import GlobalNavBranding from './global-nav-branding'; +import GlobalNavMenu from './global-nav-menu'; +import GlobalNavUser from './global-nav-user'; +import GlobalNavSearch from './global-nav-search'; +import ShortcutsHelpView from './shortcuts-help-view'; + +export default React.createClass({ + componentDidMount() { + window.addEventListener('keypress', this.onKeyPress); + }, + + componentWillUnmount() { + window.removeEventListener('keypress', this.onKeyPress); + }, + + onKeyPress(e) { + const tagName = e.target.tagName; + const code = e.keyCode || e.which; + const isInput = tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA'; + const isTriggerKey = code === 63; + const isModalOpen = document.querySelector('html').classList.contains('modal-open'); + if (!isInput && !isModalOpen && isTriggerKey) { + this.openHelp(); + } + }, + + openHelp(e) { + if (e) { + e.preventDefault(); + } + new ShortcutsHelpView().render(); + }, + + render() { + return ( +
    + + + + + +
    + ); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/search-view.js b/server/sonar-web/src/main/js/app/components/nav/global/search-view.js new file mode 100644 index 00000000000..9974ddcc284 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/global/search-view.js @@ -0,0 +1,264 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 $ from 'jquery'; +import _ from 'underscore'; +import Backbone from 'backbone'; +import Marionette from 'backbone.marionette'; +import SelectableCollectionView from '../../../../components/common/selectable-collection-view'; +import SearchItemTemplate from '../templates/nav-search-item.hbs'; +import EmptySearchTemplate from '../templates/nav-search-empty.hbs'; +import SearchTemplate from '../templates/nav-search.hbs'; +import RecentHistory from '../component/RecentHistory'; +import { translate } from '../../../../helpers/l10n'; +import { collapsedDirFromPath, fileFromPath } from '../../../../helpers/path'; + +const SearchItemView = Marionette.ItemView.extend({ + tagName: 'li', + template: SearchItemTemplate, + + select () { + this.$el.addClass('active'); + }, + + deselect () { + this.$el.removeClass('active'); + }, + + submit () { + this.$('a')[0].click(); + }, + + onRender () { + this.$('[data-toggle="tooltip"]').tooltip({ + container: 'body', + html: true, + placement: 'left', + delay: { show: 500, hide: 0 } + }); + }, + + onDestroy () { + this.$('[data-toggle="tooltip"]').tooltip('destroy'); + }, + + serializeData () { + return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), { + index: this.options.index + }); + } +}); + +const SearchEmptyView = Marionette.ItemView.extend({ + tagName: 'li', + template: EmptySearchTemplate +}); + +const SearchResultsView = SelectableCollectionView.extend({ + className: 'menu', + tagName: 'ul', + childView: SearchItemView, + emptyView: SearchEmptyView +}); + +export default Marionette.LayoutView.extend({ + className: 'navbar-search', + tagName: 'form', + template: SearchTemplate, + + regions: { + resultsRegion: '.js-search-results' + }, + + events: { + 'submit': 'onSubmit', + 'keydown .js-search-input': 'onKeyDown', + 'keyup .js-search-input': 'onKeyUp' + }, + + initialize () { + const that = this; + this.results = new Backbone.Collection(); + this.favorite = []; + if (window.SS.user) { + this.fetchFavorite().always(function () { + that.resetResultsToDefault(); + }); + } else { + this.resetResultsToDefault(); + } + this.resultsView = new SearchResultsView({ collection: this.results }); + this.debouncedSearch = _.debounce(this.search, 250); + this._bufferedValue = ''; + }, + + onRender () { + const that = this; + this.resultsRegion.show(this.resultsView); + setTimeout(function () { + that.$('.js-search-input').focus(); + }, 0); + }, + + onKeyDown (e) { + if (e.keyCode === 38) { + this.resultsView.selectPrev(); + return false; + } + if (e.keyCode === 40) { + this.resultsView.selectNext(); + return false; + } + if (e.keyCode === 13) { + this.resultsView.submitCurrent(); + this.destroy(); + return false; + } + if (e.keyCode === 27) { + this.options.hide(); + return false; + } + }, + + onKeyUp () { + const value = this.$('.js-search-input').val(); + if (value === this._bufferedValue) { + return; + } + this._bufferedValue = this.$('.js-search-input').val(); + this.searchRequest = this.debouncedSearch(value); + }, + + onSubmit () { + return false; + }, + + fetchFavorite () { + const that = this; + return $.get(window.baseUrl + '/api/favourites').done(function (r) { + that.favorite = r.map(function (f) { + const isFile = ['FIL', 'UTS'].indexOf(f.qualifier) !== -1; + return { + url: window.baseUrl + '/dashboard/index?id=' + encodeURIComponent(f.key) + window.dashboardParameters(true), + name: isFile ? collapsedDirFromPath(f.lname) + fileFromPath(f.lname) : f.name, + icon: 'favorite' + }; + }); + that.favorite = _.sortBy(that.favorite, 'name'); + }); + }, + + resetResultsToDefault () { + const recentHistory = RecentHistory.get(); + const history = recentHistory.map(function (historyItem, index) { + const url = window.baseUrl + '/dashboard/index?id=' + encodeURIComponent(historyItem.key) + + window.dashboardParameters(true); + return { + url, + name: historyItem.name, + q: historyItem.icon, + extra: index === 0 ? translate('browsed_recently') : null + }; + }); + const favorite = _.first(this.favorite, 6).map(function (f, index) { + return _.extend(f, { extra: index === 0 ? translate('favorite') : null }); + }); + this.results.reset([].concat(history, favorite)); + }, + + search (q) { + if (q.length < 2) { + this.resetResultsToDefault(); + return; + } + const that = this; + const url = window.baseUrl + '/api/components/suggestions'; + const options = { s: q }; + return $.get(url, options).done(function (r) { + // if the input value has changed since we sent the request, + // just ignore the output, because another request already sent + if (q !== that._bufferedValue) { + return; + } + + const collection = []; + r.results.forEach(function (domain) { + domain.items.forEach(function (item, index) { + collection.push(_.extend(item, { + q: domain.q, + extra: index === 0 ? domain.name : null, + url: window.baseUrl + '/dashboard/index?id=' + encodeURIComponent(item.key) + + window.dashboardParameters(true) + })); + }); + }); + that.results.reset([].concat( + that.getNavigationFindings(q), + that.getGlobalDashboardFindings(q), + that.getFavoriteFindings(q), + collection + )); + }); + }, + + getNavigationFindings (q) { + const DEFAULT_ITEMS = [ + { name: translate('issues.page'), url: window.baseUrl + '/issues/search' }, + { name: translate('layout.measures'), url: window.baseUrl + '/measures/search?qualifiers[]=TRK' }, + { name: translate('coding_rules.page'), url: window.baseUrl + '/coding_rules' }, + { name: translate('quality_profiles.page'), url: window.baseUrl + '/profiles' }, + { name: translate('quality_gates.page'), url: window.baseUrl + '/quality_gates' } + ]; + const customItems = []; + if (window.SS.isUserAdmin) { + customItems.push({ name: translate('layout.settings'), url: window.baseUrl + '/settings' }); + } + const findings = [].concat(DEFAULT_ITEMS, customItems).filter(function (f) { + return f.name.match(new RegExp(q, 'i')); + }); + if (findings.length > 0) { + findings[0].extra = translate('navigation'); + } + return _.first(findings, 6); + }, + + getGlobalDashboardFindings (q) { + const dashboards = this.model.get('globalDashboards') || []; + const items = dashboards.map(function (d) { + return { name: d.name, url: window.baseUrl + '/dashboard/index?did=' + encodeURIComponent(d.key) }; + }); + const findings = items.filter(function (f) { + return f.name.match(new RegExp(q, 'i')); + }); + if (findings.length > 0) { + findings[0].extra = translate('dashboard.global_dashboards'); + } + return _.first(findings, 6); + }, + + getFavoriteFindings (q) { + const findings = this.favorite.filter(function (f) { + return f.name.match(new RegExp(q, 'i')); + }); + if (findings.length > 0) { + findings[0].extra = translate('favorite'); + } + return _.first(findings, 6); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/shortcuts-help-view.js b/server/sonar-web/src/main/js/app/components/nav/global/shortcuts-help-view.js new file mode 100644 index 00000000000..ca4f2f5ac97 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/global/shortcuts-help-view.js @@ -0,0 +1,27 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 ModalView from '../../../../components/common/modals'; +import ShortcutsHelpTemplate from '../templates/nav-shortcuts-help.hbs'; + +export default ModalView.extend({ + className: 'modal modal-large', + template: ShortcutsHelpTemplate +}); + diff --git a/server/sonar-web/src/main/js/app/components/nav/links-mixin.js b/server/sonar-web/src/main/js/app/components/nav/links-mixin.js new file mode 100644 index 00000000000..0027e2250df --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/links-mixin.js @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import classNames from 'classnames'; + +export default { + activeLink(url) { + return window.location.pathname.indexOf(window.baseUrl + url) === 0 ? 'active' : null; + }, + + renderLink(url, title, highlightUrl = url) { + const fullUrl = window.baseUrl + url; + const isActive = typeof highlightUrl === 'string' ? + window.location.pathname.indexOf(window.baseUrl + highlightUrl) === 0 : + highlightUrl(fullUrl); + + return ( +
  • + {title} +
  • + ); + } +}; diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/settings-nav.js b/server/sonar-web/src/main/js/app/components/nav/settings/settings-nav.js new file mode 100644 index 00000000000..087064ed84c --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/settings/settings-nav.js @@ -0,0 +1,133 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import classNames from 'classnames'; +import some from 'lodash/some'; +import LinksMixin from '../links-mixin'; +import { translate } from '../../../../helpers/l10n'; + +export default React.createClass({ + mixins: [LinksMixin], + + getDefaultProps() { + return { extensions: [] }; + }, + + isSomethingActive(urls) { + const path = window.location.pathname; + return some(urls, url => path.indexOf(window.baseUrl + url) === 0); + }, + + isSecurityActive() { + const urls = ['/users', '/groups', '/roles/global', '/permission_templates']; + return this.isSomethingActive(urls); + }, + + isProjectsActive() { + const urls = ['/projects_admin', '/background_tasks']; + return this.isSomethingActive(urls); + }, + + isSystemActive() { + const urls = ['/updatecenter', '/system']; + return this.isSomethingActive(urls); + }, + + render() { + const isSecurity = this.isSecurityActive(); + const isProjects = this.isProjectsActive(); + const isSystem = this.isSystemActive(); + + const securityClassName = classNames('dropdown', { active: isSecurity }); + const projectsClassName = classNames('dropdown', { active: isProjects }); + const systemClassName = classNames('dropdown', { active: isSystem }); + const configurationClassNames = classNames('dropdown', { + active: !isSecurity && !isProjects && !isSystem + }); + + return ( +
    +
      + {this.renderLink('/settings', translate('layout.settings'))} +
    + +
      +
    • + + {translate('sidebar.project_settings')} + {' '} + + +
        + {this.renderLink('/settings', translate('settings.page'), url => window.location.pathname === url)} + {this.renderLink('/settings/licenses', translate('property.category.licenses'))} + {this.renderLink('/settings/encryption', translate('property.category.security.encryption'))} + {this.renderLink('/settings/server_id', translate('property.category.server_id'))} + {this.renderLink('/metrics', 'Custom Metrics')} + {this.props.extensions.map(e => this.renderLink(e.url, e.name))} +
      +
    • + +
    • + + {translate('sidebar.security')} + {' '} + + +
        + {this.renderLink('/users', translate('users.page'))} + {this.renderLink('/groups', translate('user_groups.page'))} + {this.renderLink('/roles/global', + translate('global_permissions.page'))} + {this.renderLink('/permission_templates', + translate('permission_templates'))} +
      +
    • + +
    • + + {translate('sidebar.projects')} + {' '} + + +
        + {this.renderLink('/projects_admin', 'Management')} + {this.renderLink('/background_tasks', + translate('background_tasks.page'))} +
      +
    • + +
    • + + {translate('sidebar.system')} + {' '} + + +
        + {this.renderLink('/updatecenter', translate('update_center.page'))} + {this.renderLink('/system', translate('system_info.page'))} +
      +
    • +
    +
    + + ); + } +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/templates/nav-search-empty.hbs b/server/sonar-web/src/main/js/app/components/nav/templates/nav-search-empty.hbs new file mode 100644 index 00000000000..fb76e686612 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/templates/nav-search-empty.hbs @@ -0,0 +1 @@ +{{t 'no_results'}} diff --git a/server/sonar-web/src/main/js/app/components/nav/templates/nav-search-item.hbs b/server/sonar-web/src/main/js/app/components/nav/templates/nav-search-item.hbs new file mode 100644 index 00000000000..25128ddfc20 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/templates/nav-search-item.hbs @@ -0,0 +1,22 @@ +{{#notNull extra}} + {{#gt index 0}} +
    + {{/gt}} + {{#if extra}} + + {{/if}} +{{/notNull}} + + + {{#if icon}}{{/if}} + {{#if q}}{{qualifierIcon q}}{{/if}} + {{#eq q 'FIL'}} + {{collapsedDirFromPath name}}{{fileFromPath name}} + {{else}} + {{#eq q 'UTS'}} + {{collapsedDirFromPath name}}{{fileFromPath name}} + {{else}} + {{name}} + {{/eq}} + {{/eq}} + diff --git a/server/sonar-web/src/main/js/app/components/nav/templates/nav-search.hbs b/server/sonar-web/src/main/js/app/components/nav/templates/nav-search.hbs new file mode 100644 index 00000000000..68e1f3ad168 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/templates/nav-search.hbs @@ -0,0 +1,8 @@ + + + + +
    + + diff --git a/server/sonar-web/src/main/js/app/components/nav/templates/nav-shortcuts-help.hbs b/server/sonar-web/src/main/js/app/components/nav/templates/nav-shortcuts-help.hbs new file mode 100644 index 00000000000..ae4f9967233 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/templates/nav-shortcuts-help.hbs @@ -0,0 +1,61 @@ + + + + + diff --git a/server/sonar-web/src/main/js/app/index.js b/server/sonar-web/src/main/js/app/index.js index 3ed7485fed3..65145e45906 100644 --- a/server/sonar-web/src/main/js/app/index.js +++ b/server/sonar-web/src/main/js/app/index.js @@ -17,41 +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 React from 'react'; -import { render } from 'react-dom'; -import { Router, Route, useRouterHistory } from 'react-router'; -import { createHistory } from 'history'; -import { Provider } from 'react-redux'; -import App from './components/App'; -import aboutRoutes from '../apps/about/routes'; -import accountRoutes from '../apps/account/routes'; -import projectsRoutes from '../apps/projects/routes'; -import qualityGatesRoutes from '../apps/quality-gates/routes'; -import qualityProfilesRoutes from '../apps/quality-profiles/routes'; -import configureStore from '../components/store/configureStore'; -import rootReducer from './store/rootReducer'; +import configureLocale from './utils/configureLocale'; +import exposeLibraries from './utils/exposeLibraries'; +import startAjaxMonitoring from './utils/startAjaxMonitoring'; +import startApp from './utils/startApp'; +import startReactApp from './utils/startReactApp'; import './styles/index'; -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - - const history = useRouterHistory(createHistory)({ - basename: window.baseUrl + '/' - }); - - const store = configureStore(rootReducer); - - render(( - - - - {aboutRoutes} - {accountRoutes} - {projectsRoutes} - {qualityGatesRoutes} - {qualityProfilesRoutes} - - - - ), el); -}); +configureLocale(); +startAjaxMonitoring(); +startApp(); +startReactApp(); +exposeLibraries(); diff --git a/server/sonar-web/src/main/js/app/store/rootReducer.js b/server/sonar-web/src/main/js/app/store/rootReducer.js index 40c02dafbf7..396c2b5c5f8 100644 --- a/server/sonar-web/src/main/js/app/store/rootReducer.js +++ b/server/sonar-web/src/main/js/app/store/rootReducer.js @@ -25,8 +25,12 @@ import languages, * as fromLanguages from './languages/reducer'; import measures, * as fromMeasures from './measures/reducer'; import globalMessages, * as fromGlobalMessages from '../../components/store/globalMessages'; +import measuresApp, * as fromMeasuresApp from '../../apps/component-measures/store/rootReducer'; +import permissionsApp, * as fromPermissionsApp from '../../apps/permissions/shared/store/rootReducer'; +import projectAdminApp, * as fromProjectAdminApp from '../../apps/project-admin/store/rootReducer'; import projectsApp, * as fromProjectsApp from '../../apps/projects/store/reducer'; import qualityGatesApp from '../../apps/quality-gates/store/rootReducer'; +import settingsApp, * as fromSettingsApp from '../../apps/settings/store/rootReducer'; export default combineReducers({ components, @@ -37,8 +41,12 @@ export default combineReducers({ users, // apps + measuresApp, + permissionsApp, + projectAdminApp, projectsApp, - qualityGatesApp + qualityGatesApp, + settingsApp }); export const getComponent = (state, key) => ( @@ -88,3 +96,199 @@ export const getProjectsAppMaxFacetValue = state => ( export const getQualityGatesAppState = state => ( state.qualityGatesApp ); + +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 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) => ( + fromSettingsApp.getSettingsForCategory(state.settingsApp, category) +); + +export const getSettingsAppChangedValue = (state, key) => ( + fromSettingsApp.getChangedValue(state.settingsApp, key) +); + +export const isSettingsAppLoading = (state, key) => ( + fromSettingsApp.isLoading(state.settingsApp, key) +); + +export const getSettingsAppLicenseByKey = (state, key) => ( + fromSettingsApp.getLicenseByKey(state.settingsApp, key) +); + +export const getSettingsAppAllLicenseKeys = state => ( + fromSettingsApp.getAllLicenseKeys(state.settingsApp) +); + +export const getSettingsAppValidationMessage = (state, key) => ( + fromSettingsApp.getValidationMessage(state.settingsApp, key) +); + +export const getSettingsAppEncryptionState = state => ( + fromSettingsApp.getEncryptionState(state.settingsApp) +); + +export const getSettingsAppGlobalMessages = state => ( + fromSettingsApp.getGlobalMessages(state.settingsApp) +); + +export const getProjectAdminProfileByKey = (state, profileKey) => ( + fromProjectAdminApp.getProfileByKey(state.projectAdminApp, profileKey) +); + +export const getProjectAdminAllProfiles = state => ( + fromProjectAdminApp.getAllProfiles(state.projectAdminApp) +); + +export const getProjectAdminProjectProfiles = (state, projectKey) => ( + fromProjectAdminApp.getProjectProfiles(state.projectAdminApp, projectKey) +); + +export const getProjectAdminGateById = (state, gateId) => ( + fromProjectAdminApp.getGateById(state.projectAdminApp, gateId) +); + +export const getProjectAdminAllGates = state => ( + fromProjectAdminApp.getAllGates(state.projectAdminApp) +); + +export const getProjectAdminProjectGate = (state, projectKey) => ( + fromProjectAdminApp.getProjectGate(state.projectAdminApp, projectKey) +); + +export const getProjectAdminLinkById = (state, linkId) => ( + fromProjectAdminApp.getLinkById(state.projectAdminApp, linkId) +); + +export const getProjectAdminProjectLinks = (state, projectKey) => ( + fromProjectAdminApp.getProjectLinks(state.projectAdminApp, projectKey) +); + +export const getProjectAdminComponentByKey = (state, componentKey) => ( + fromProjectAdminApp.getComponentByKey(state.projectAdminApp, componentKey) +); + +export const getProjectAdminProjectModules = (state, projectKey) => ( + fromProjectAdminApp.getProjectModules(state.projectAdminApp, projectKey) +); + +export const getProjectAdminGlobalMessages = state => ( + fromProjectAdminApp.getGlobalMessages(state.projectAdminApp) +); + +export const getMeasuresAppComponent = state => ( + fromMeasuresApp.getComponent(state.measuresApp) +); + +export const getMeasuresAppAllMetrics = state => ( + fromMeasuresApp.getAllMetrics(state.measuresApp) +); + +export const getMeasuresAppDetailsMetric = state => ( + fromMeasuresApp.getDetailsMetric(state.measuresApp) +); + +export const getMeasuresAppDetailsMeasure = state => ( + fromMeasuresApp.getDetailsMeasure(state.measuresApp) +); + +export const getMeasuresAppDetailsSecondaryMeasure = state => ( + fromMeasuresApp.getDetailsSecondaryMeasure(state.measuresApp) +); + +export const getMeasuresAppDetailsPeriods = state => ( + fromMeasuresApp.getDetailsPeriods(state.measuresApp) +); + +export const isMeasuresAppFetching = state => ( + fromMeasuresApp.isFetching(state.measuresApp) +); + +export const getMeasuresAppList = state => ( + fromMeasuresApp.getList(state.measuresApp) +); + +export const getMeasuresAppListComponents = state => ( + fromMeasuresApp.getListComponents(state.measuresApp) +); + +export const getMeasuresAppListSelected = state => ( + fromMeasuresApp.getListSelected(state.measuresApp) +); + +export const getMeasuresAppListTotal = state => ( + fromMeasuresApp.getListTotal(state.measuresApp) +); + +export const getMeasuresAppListPageIndex = state => ( + fromMeasuresApp.getListPageIndex(state.measuresApp) +); + +export const getMeasuresAppTree = state => ( + fromMeasuresApp.getTree(state.measuresApp) +); + +export const getMeasuresAppTreeComponents = state => ( + fromMeasuresApp.getTreeComponents(state.measuresApp) +); + +export const getMeasuresAppTreeBreadcrumbs = state => ( + fromMeasuresApp.getTreeBreadcrumbs(state.measuresApp) +); + +export const getMeasuresAppTreeSelected = state => ( + fromMeasuresApp.getTreeSelected(state.measuresApp) +); + +export const getMeasuresAppTreeTotal = state => ( + fromMeasuresApp.getTreeTotal(state.measuresApp) +); + +export const getMeasuresAppTreePageIndex = state => ( + fromMeasuresApp.getTreePageIndex(state.measuresApp) +); + +export const getMeasuresAppHomeDomains = state => ( + fromMeasuresApp.getHomeDomains(state.measuresApp) +); + +export const getMeasuresAppHomePeriods = state => ( + fromMeasuresApp.getHomePeriods(state.measuresApp) +); diff --git a/server/sonar-web/src/main/js/app/styles/index.js b/server/sonar-web/src/main/js/app/styles/index.js index 0f7e68f8ed3..24defb8b3f1 100644 --- a/server/sonar-web/src/main/js/app/styles/index.js +++ b/server/sonar-web/src/main/js/app/styles/index.js @@ -17,5 +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 '../../components/ui/Level.css'; +import '../../components/ui/Rating.css'; import './boxed-group.css'; import './page.css'; + +// these styles are extracted to a separate file +import '../../../less/sonar.less'; diff --git a/server/sonar-web/src/main/js/app/utils/configureLocale.js b/server/sonar-web/src/main/js/app/utils/configureLocale.js new file mode 100644 index 00000000000..d035798783b --- /dev/null +++ b/server/sonar-web/src/main/js/app/utils/configureLocale.js @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 moment from 'moment'; + +const getPreferredLanguage = () => ( + window.navigator.languages ? window.navigator.languages[0] : window.navigator.language +); + +const configureLocale = () => { + moment.locale(getPreferredLanguage()); +}; + +export default configureLocale; diff --git a/server/sonar-web/src/main/js/app/utils/exposeLibraries.js b/server/sonar-web/src/main/js/app/utils/exposeLibraries.js new file mode 100644 index 00000000000..92580bae1c0 --- /dev/null +++ b/server/sonar-web/src/main/js/app/utils/exposeLibraries.js @@ -0,0 +1,28 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 measures from '../../helpers/measures'; +import * as request from '../../helpers/request'; + +const exposeLibraries = () => { + window.SonarMeasures = measures; + window.SonarRequest = request; +}; + +export default exposeLibraries; diff --git a/server/sonar-web/src/main/js/app/utils/isCurrentPathKnown.js b/server/sonar-web/src/main/js/app/utils/isCurrentPathKnown.js new file mode 100644 index 00000000000..37468ca94f4 --- /dev/null +++ b/server/sonar-web/src/main/js/app/utils/isCurrentPathKnown.js @@ -0,0 +1,69 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +const knownPaths = [ + 'about', + 'account', + 'background_tasks', + 'coding_rules', + 'dashboard', + 'groups', + 'issues', + 'maintenance', + 'metrics', + 'permission_templates', + 'projects', + 'projects_admin', + 'roles/global', + 'settings', + 'setup', + 'system', + 'quality_gates', + 'profiles', + 'updatecenter', + 'users', + 'web_api', + 'code', + 'component_issues', + 'component_measures', + 'custom_measures', + 'project/background_tasks', + 'project/settings', + 'project/deletion', + 'project/quality_profiles', + 'project/quality_gate', + 'project/links', + 'project/key', + 'project_roles' +]; + +const ignoredPaths = [ + 'users/new' +]; + +export default function () { + const currentPath = window.location.pathname; + + const isIgnored = ignoredPaths.some(path => currentPath.indexOf(`${window.baseUrl}/${path}`) === 0); + if (isIgnored) { + return false; + } + + return knownPaths.some(path => currentPath.indexOf(`${window.baseUrl}/${path}`) === 0); +} diff --git a/server/sonar-web/src/main/js/app/utils/startAjaxMonitoring.js b/server/sonar-web/src/main/js/app/utils/startAjaxMonitoring.js new file mode 100644 index 00000000000..cc3f75823db --- /dev/null +++ b/server/sonar-web/src/main/js/app/utils/startAjaxMonitoring.js @@ -0,0 +1,192 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 $ from 'jquery'; +import _ from 'underscore'; +import Backbone from 'backbone'; +import Marionette from 'backbone.marionette'; +import escapeHtml from 'escape-html'; +import { translate } from '../../helpers/l10n'; +import { getCSRFTokenName, getCSRFTokenValue } from '../../helpers/request'; + +const defaults = { + queue: {}, + timeout: 300, + fadeTimeout: 100 +}; + +const Process = Backbone.Model.extend({ + defaults: { + state: 'ok' + }, + + timeout () { + this.set({ + state: 'timeout', + message: 'Still Working...' + }); + }, + + finish (options) { + options = _.defaults(options || {}, { force: false }); + if (this.get('state') !== 'failed' || !!options.force) { + this.trigger('destroy', this, this.collection, options); + } + }, + + fail (message) { + const that = this; + let msg = message || translate('process.fail'); + if (msg === 'process.fail') { + // no translation + msg = 'An error happened, some parts of the page might not render correctly. ' + + 'Please contact the administrator if you keep on experiencing this error.'; + } + clearInterval(this.get('timer')); + this.set({ + state: 'failed', + message: msg + }); + this.set('state', 'failed'); + setTimeout(function () { + that.finish({ force: true }); + }, 5000); + } +}); + +const Processes = Backbone.Collection.extend({ + model: Process +}); + +const ProcessesView = Marionette.ItemView.extend({ + tagName: 'ul', + className: 'processes-container', + + collectionEvents: { + 'all': 'render' + }, + + render () { + const failed = this.collection.findWhere({ state: 'failed' }); + const timeout = this.collection.findWhere({ state: 'timeout' }); + let el; + this.$el.empty(); + if (failed != null) { + el = $('
  • ') + .html(failed.get('message')) + .addClass('process-spinner process-spinner-failed shown'); + const close = $('').html('').addClass('process-spinner-close'); + close.appendTo(el); + close.on('click', function () { + failed.finish({ force: true }); + }); + el.appendTo(this.$el); + } else if (timeout != null) { + el = $('
  • ') + .html(timeout.get('message')) + .addClass('process-spinner shown'); + el.appendTo(this.$el); + } + return this; + } +}); + +const processes = new Processes(); +const processesView = new ProcessesView({ + collection: processes +}); + +/** + * Add background process + * @returns {number} + */ +function addBackgroundProcess () { + const uid = _.uniqueId('process'); + const process = new Process({ + id: uid, + timer: setTimeout(function () { + process.timeout(); + }, defaults.timeout) + }); + processes.add(process); + return uid; +} + +/** + * Finish background process + * @param {number} uid + */ +function finishBackgroundProcess (uid) { + const process = processes.get(uid); + if (process != null) { + process.finish(); + } +} + +/** + * Fail background process + * @param {number} uid + * @param {string} message + */ +function failBackgroundProcess (uid, message) { + const process = processes.get(uid); + if (process != null) { + process.fail(message); + } +} + +/** + * Handle ajax error + * @param jqXHR + */ +function handleAjaxError (jqXHR) { + if (jqXHR != null && jqXHR.processId != null) { + let message = null; + if (jqXHR.responseJSON != null && jqXHR.responseJSON.errors != null) { + message = _.pluck(jqXHR.responseJSON.errors, 'msg').join('. '); + } + failBackgroundProcess(jqXHR.processId, message ? escapeHtml(message) : null); + } +} + +$.ajaxSetup({ + beforeSend (jqXHR) { + jqXHR.setRequestHeader(getCSRFTokenName(), getCSRFTokenValue()); + jqXHR.processId = addBackgroundProcess(); + }, + complete (jqXHR) { + if (jqXHR.processId != null) { + finishBackgroundProcess(jqXHR.processId); + } + }, + statusCode: { + 400: handleAjaxError, + 403: handleAjaxError, + 500: handleAjaxError, + 502: handleAjaxError, + 503: handleAjaxError, + 504: handleAjaxError + } +}); + +const startAjaxMonitoring = () => { + processesView.render().$el.insertBefore('#footer'); +}; + +export default startAjaxMonitoring; diff --git a/server/sonar-web/src/main/js/app/utils/startApp.js b/server/sonar-web/src/main/js/app/utils/startApp.js new file mode 100644 index 00000000000..9229702f16d --- /dev/null +++ b/server/sonar-web/src/main/js/app/utils/startApp.js @@ -0,0 +1,69 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 _ from 'underscore'; +import Navigation from '../components/nav/app'; +import { installGlobal, requestMessages } from '../../helpers/l10n'; + +function requestLocalizationBundle () { + if (!window.sonarqube.bannedNavigation) { + installGlobal(); + return requestMessages(); + } else { + return Promise.resolve(); + } +} + +function startNavigation () { + if (!window.sonarqube.bannedNavigation) { + return new Navigation().start(); + } else { + return Promise.resolve(); + } +} + +function prepareAppOptions (navResponse) { + const appOptions = { el: '#content' }; + if (navResponse) { + appOptions.rootQualifiers = navResponse.global.qualifiers; + appOptions.logoUrl = navResponse.global.logoUrl; + appOptions.logoWidth = navResponse.global.logoWidth; + if (navResponse.component) { + appOptions.component = { + id: navResponse.component.uuid, + key: navResponse.component.key, + name: navResponse.component.name, + qualifier: _.last(navResponse.component.breadcrumbs).qualifier, + breadcrumbs: navResponse.component.breadcrumbs, + snapshotDate: navResponse.component.snapshotDate + }; + } + } + return appOptions; +} + +const startApp = () => { + window.sonarqube.appStarted = Promise.resolve() + .then(requestLocalizationBundle) + .then(startNavigation) + .then(prepareAppOptions); +}; + +export default startApp; + diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.js b/server/sonar-web/src/main/js/app/utils/startReactApp.js new file mode 100644 index 00000000000..31b5aac4197 --- /dev/null +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.js @@ -0,0 +1,116 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { render } from 'react-dom'; +import { Router, Route, useRouterHistory } from 'react-router'; +import { createHistory } from 'history'; +import { Provider } from 'react-redux'; +import App from '../components/App'; +import ComponentContainer from '../components/ComponentContainer'; +import NullComponent from '../components/NullComponent'; +import aboutRoutes from '../../apps/about/routes'; +import accountRoutes from '../../apps/account/routes'; +import backgroundTasksRoutes from '../../apps/background-tasks/routes'; +import codeRoutes from '../../apps/code/routes'; +import codingRulesRoutes from '../../apps/coding-rules/routes'; +import componentIssuesRoutes from '../../apps/component-issues/routes'; +import componentMeasuresRoutes from '../../apps/component-measures/routes'; +import customMeasuresRoutes from '../../apps/custom-measures/routes'; +import groupsRoutes from '../../apps/groups/routes'; +import issuesRoutes from '../../apps/issues/routes'; +import metricsRoutes from '../../apps/metrics/routes'; +import overviewRoutes from '../../apps/overview/routes'; +import permissionTemplatesRoutes from '../../apps/permission-templates/routes'; +import projectAdminRoutes from '../../apps/project-admin/routes'; +import projectsRoutes from '../../apps/projects/routes'; +import projectsAdminRoutes from '../../apps/projects-admin/routes'; +import qualityGatesRoutes from '../../apps/quality-gates/routes'; +import qualityProfilesRoutes from '../../apps/quality-profiles/routes'; +import settingsRoutes from '../../apps/settings/routes'; +import systemRoutes from '../../apps/system/routes'; +import updateCenterRoutes from '../../apps/update-center/routes'; +import usersRoutes from '../../apps/users/routes'; +import webAPIRoutes from '../../apps/web-api/routes'; +import { maintenanceRoutes, setupRoutes } from '../../apps/maintenance/routes'; +import { globalPermissionsRoutes, projectPermissionsRoutes } from '../../apps/permissions/routes'; +import configureStore from '../../components/store/configureStore'; +import rootReducer from '../store/rootReducer'; +import isCurrentPathKnown from './isCurrentPathKnown'; + +const startReactApp = () => { + if (isCurrentPathKnown()) { + window.sonarqube.appStarted.then(options => { + const el = document.querySelector(options.el); + + const history = useRouterHistory(createHistory)({ + basename: window.baseUrl + '/' + }); + + const store = configureStore(rootReducer); + + render(( + + + + {aboutRoutes} + {accountRoutes} + {backgroundTasksRoutes} + {codingRulesRoutes} + {overviewRoutes} + {groupsRoutes} + {issuesRoutes} + {maintenanceRoutes} + {metricsRoutes} + {permissionTemplatesRoutes} + {projectsRoutes} + {projectsAdminRoutes} + {globalPermissionsRoutes} + {settingsRoutes} + {setupRoutes} + {systemRoutes} + {qualityGatesRoutes} + {qualityProfilesRoutes} + {updateCenterRoutes} + {usersRoutes} + {webAPIRoutes} + + + {codeRoutes} + {componentIssuesRoutes} + {componentMeasuresRoutes} + {customMeasuresRoutes} + + {backgroundTasksRoutes} + {settingsRoutes} + {projectAdminRoutes} + + {projectPermissionsRoutes} + + + + + + + ), el); + }); + } +}; + +export default startReactApp; diff --git a/server/sonar-web/src/main/js/apps/background-tasks/app.js b/server/sonar-web/src/main/js/apps/background-tasks/app.js deleted file mode 100644 index 849bd897cb7..00000000000 --- a/server/sonar-web/src/main/js/apps/background-tasks/app.js +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - /* @flow */ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { Router, Route, Redirect, useRouterHistory } from 'react-router'; -import { createHistory } from 'history'; - -import BackgroundTasksApp from './components/BackgroundTasksApp'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - - const history = useRouterHistory(createHistory)({ - basename: window.baseUrl + (options.component ? '/project/background_tasks' : '/background_tasks') - }); - - const App = props => ; - - ReactDOM.render(( - - - - - ), el); -}); diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js b/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js index 5beee99c9af..0fa65014b61 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js @@ -21,7 +21,6 @@ import React from 'react'; import shallowCompare from 'react-addons-shallow-compare'; import debounce from 'lodash/debounce'; -import { PropTypes as RouterPropTypes } from 'react-router'; import { DEFAULT_FILTERS, DEBOUNCE_DELAY, STATUSES, CURRENTS } from './../constants'; import Header from './Header'; @@ -41,7 +40,7 @@ export default class BackgroundTasksApp extends React.Component { static propTypes = { component: React.PropTypes.object, - location: RouterPropTypes.location.isRequired + location: React.PropTypes.object }; state: any = { @@ -136,7 +135,7 @@ export default class BackgroundTasksApp extends React.Component { }); this.context.router.push({ - pathname: '/', + pathname: this.props.location.pathname, query: nextQuery }); } diff --git a/server/sonar-web/src/main/js/apps/background-tasks/routes.js b/server/sonar-web/src/main/js/apps/background-tasks/routes.js new file mode 100644 index 00000000000..5bbcd616795 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import BackgroundTasksApp from './components/BackgroundTasksApp'; + +export default ( + +); diff --git a/server/sonar-web/src/main/js/apps/code/app.js b/server/sonar-web/src/main/js/apps/code/app.js deleted file mode 100644 index fc13bb30a31..00000000000 --- a/server/sonar-web/src/main/js/apps/code/app.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { render } from 'react-dom'; -import { Router, Route, Redirect, useRouterHistory } from 'react-router'; -import { createHistory } from 'history'; - -import App from './components/App'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - - const history = useRouterHistory(createHistory)({ - basename: window.baseUrl + '/code' - }); - - const AppWithComponent = (props) => { - return ; - }; - - render(( - - - - - ), el); -}); diff --git a/server/sonar-web/src/main/js/apps/code/components/ComponentName.js b/server/sonar-web/src/main/js/apps/code/components/ComponentName.js index cfe56f47381..ae166bbaa02 100644 --- a/server/sonar-web/src/main/js/apps/code/components/ComponentName.js +++ b/server/sonar-web/src/main/js/apps/code/components/ComponentName.js @@ -48,7 +48,7 @@ function mostCommitPrefix (strings) { return prefix.substr(0, prefix.length - lastPrefixPart.length); } -const Component = ({ component, rootComponent, previous, canBrowse }) => { +const ComponentName = ({ component, rootComponent, previous, canBrowse }) => { const areBothDirs = component.qualifier === 'DIR' && previous && previous.qualifier === 'DIR'; const prefix = areBothDirs ? mostCommitPrefix([component.name + '/', previous.name + '/']) : ''; const name = prefix ? ( @@ -75,7 +75,7 @@ const Component = ({ component, rootComponent, previous, canBrowse }) => { Object.assign(query, { selected: component.key }); } inner = ( - + {' '} {name} @@ -99,4 +99,4 @@ const Component = ({ component, rootComponent, previous, canBrowse }) => { ); }; -export default Component; +export default ComponentName; diff --git a/server/sonar-web/src/main/js/apps/code/components/Search.js b/server/sonar-web/src/main/js/apps/code/components/Search.js index d54f727e5f3..659b397074c 100644 --- a/server/sonar-web/src/main/js/apps/code/components/Search.js +++ b/server/sonar-web/src/main/js/apps/code/components/Search.js @@ -103,7 +103,7 @@ export default class Search extends React.Component { window.location = getComponentUrl(selected.refKey); } else { this.context.router.push({ - pathname: '/', + pathname: '/code', query: { id: component.key, selected: selected.key diff --git a/server/sonar-web/src/main/js/apps/code/routes.js b/server/sonar-web/src/main/js/apps/code/routes.js new file mode 100644 index 00000000000..882c1b76882 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/code/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import App from './components/App'; + +export default ( + +); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/app.js b/server/sonar-web/src/main/js/apps/coding-rules/app.js deleted file mode 100644 index ea4adc1cf3f..00000000000 --- a/server/sonar-web/src/main/js/apps/coding-rules/app.js +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 $ from 'jquery'; -import _ from 'underscore'; -import Backbone from 'backbone'; -import Marionette from 'backbone.marionette'; -import State from './models/state'; -import Layout from './layout'; -import Rules from './models/rules'; -import Facets from '../../components/navigator/models/facets'; -import Controller from './controller'; -import Router from '../../components/navigator/router'; -import WorkspaceListView from './workspace-list-view'; -import WorkspaceHeaderView from './workspace-header-view'; -import FacetsView from './facets-view'; -import FiltersView from './filters-view'; - -const App = new Marionette.Application(); -const init = function () { - const options = window.sonarqube; - - this.layout = new Layout({ el: options.el }); - this.layout.render(); - $('#footer').addClass('search-navigator-footer'); - - this.state = new State(); - this.list = new Rules(); - this.facets = new Facets(); - - this.controller = new Controller({ app: this }); - - this.workspaceListView = new WorkspaceListView({ - app: this, - collection: this.list - }); - this.layout.workspaceListRegion.show(this.workspaceListView); - this.workspaceListView.bindScrollEvents(); - - this.workspaceHeaderView = new WorkspaceHeaderView({ - app: this, - collection: this.list - }); - this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView); - - this.facetsView = new FacetsView({ - app: this, - collection: this.facets - }); - this.layout.facetsRegion.show(this.facetsView); - - this.filtersView = new FiltersView({ - app: this - }); - this.layout.filtersRegion.show(this.filtersView); - - key.setScope('list'); - this.router = new Router({ - app: this - }); - Backbone.history.start(); -}; - -const appXHR = $.get(window.baseUrl + '/api/rules/app').done(function (r) { - App.canWrite = r.canWrite; - App.qualityProfiles = _.sortBy(r.qualityprofiles, ['name', 'lang']); - App.languages = _.extend(r.languages, { - none: 'None' - }); - _.map(App.qualityProfiles, function (profile) { - profile.language = App.languages[profile.lang]; - }); - App.repositories = r.repositories; - App.statuses = r.statuses; -}); - -App.on('start', function (options) { - appXHR.done(function () { - init.call(App, options); - }); -}); - -window.sonarqube.appStarted.then(options => App.start(options)); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js b/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js new file mode 100644 index 00000000000..97491378c7f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import init from '../init'; + +export default class CodingRulesAppContainer extends React.Component { + componentDidMount () { + init(this.refs.container); + } + + render () { + return
    ; + } +} diff --git a/server/sonar-web/src/main/js/apps/coding-rules/init.js b/server/sonar-web/src/main/js/apps/coding-rules/init.js new file mode 100644 index 00000000000..aa7c9644ede --- /dev/null +++ b/server/sonar-web/src/main/js/apps/coding-rules/init.js @@ -0,0 +1,94 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 $ from 'jquery'; +import _ from 'underscore'; +import Backbone from 'backbone'; +import Marionette from 'backbone.marionette'; +import State from './models/state'; +import Layout from './layout'; +import Rules from './models/rules'; +import Facets from '../../components/navigator/models/facets'; +import Controller from './controller'; +import Router from '../../components/navigator/router'; +import WorkspaceListView from './workspace-list-view'; +import WorkspaceHeaderView from './workspace-header-view'; +import FacetsView from './facets-view'; +import FiltersView from './filters-view'; + +const App = new Marionette.Application(); + +App.on('start', function (el) { + $.get(window.baseUrl + '/api/rules/app').done(function (r) { + App.canWrite = r.canWrite; + App.qualityProfiles = _.sortBy(r.qualityprofiles, ['name', 'lang']); + App.languages = _.extend(r.languages, { + none: 'None' + }); + _.map(App.qualityProfiles, function (profile) { + profile.language = App.languages[profile.lang]; + }); + App.repositories = r.repositories; + App.statuses = r.statuses; + }).done(() => { + this.layout = new Layout({ el }); + this.layout.render(); + $('#footer').addClass('search-navigator-footer'); + + this.state = new State(); + this.list = new Rules(); + this.facets = new Facets(); + + this.controller = new Controller({ app: this }); + + this.workspaceListView = new WorkspaceListView({ + app: this, + collection: this.list + }); + this.layout.workspaceListRegion.show(this.workspaceListView); + this.workspaceListView.bindScrollEvents(); + + this.workspaceHeaderView = new WorkspaceHeaderView({ + app: this, + collection: this.list + }); + this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView); + + this.facetsView = new FacetsView({ + app: this, + collection: this.facets + }); + this.layout.facetsRegion.show(this.facetsView); + + this.filtersView = new FiltersView({ + app: this + }); + this.layout.filtersRegion.show(this.filtersView); + + key.setScope('list'); + this.router = new Router({ + app: this + }); + Backbone.history.start(); + }); +}); + +export default function (el) { + App.start(el); +} diff --git a/server/sonar-web/src/main/js/apps/coding-rules/routes.js b/server/sonar-web/src/main/js/apps/coding-rules/routes.js new file mode 100644 index 00000000000..9688c9e7819 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/coding-rules/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import CodingRulesAppContainer from './components/CodingRulesAppContainer'; + +export default ( + +); diff --git a/server/sonar-web/src/main/js/apps/component-issues/app.js b/server/sonar-web/src/main/js/apps/component-issues/app.js deleted file mode 100644 index 7397e84eed9..00000000000 --- a/server/sonar-web/src/main/js/apps/component-issues/app.js +++ /dev/null @@ -1,116 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 $ from 'jquery'; -import _ from 'underscore'; -import Backbone from 'backbone'; -import Marionette from 'backbone.marionette'; -import State from '../issues/models/state'; -import Layout from '../issues/layout'; -import Issues from '../issues/models/issues'; -import Facets from '../../components/navigator/models/facets'; -import Controller from '../issues/controller'; -import Router from '../issues/router'; -import WorkspaceListView from '../issues/workspace-list-view'; -import WorkspaceHeaderView from '../issues/workspace-header-view'; -import FacetsView from './../issues/facets-view'; -import HeaderView from './../issues/HeaderView'; - -const App = new Marionette.Application(); -const init = function () { - const options = window.sonarqube; - - this.config = options.config; - this.state = new State({ - canBulkChange: !!window.SS.user, - isContext: true, - contextQuery: { componentUuids: options.config.resource }, - contextComponentUuid: options.config.resource, - contextComponentName: options.config.resourceName, - contextComponentQualifier: options.config.resourceQualifier - }); - this.updateContextFacets(); - this.list = new Issues(); - this.facets = new Facets(); - - this.layout = new Layout({ app: this, el: options.el }); - this.layout.render(); - $('#footer').addClass('search-navigator-footer'); - - this.controller = new Controller({ app: this }); - - this.issuesView = new WorkspaceListView({ - app: this, - collection: this.list - }); - this.layout.workspaceListRegion.show(this.issuesView); - this.issuesView.bindScrollEvents(); - - this.workspaceHeaderView = new WorkspaceHeaderView({ - app: this, - collection: this.list - }); - this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView); - - this.facetsView = new FacetsView({ - app: this, - collection: this.facets - }); - this.layout.facetsRegion.show(this.facetsView); - - this.headerView = new HeaderView({ - app: this - }); - this.layout.filtersRegion.show(this.headerView); - - key.setScope('list'); - App.router = new Router({ app: App }); - Backbone.history.start(); -}; - -App.getContextQuery = function () { - return { componentUuids: this.config.resource }; -}; - -App.getRestrictedFacets = function () { - return { - 'TRK': ['projectUuids'], - 'BRC': ['projectUuids'], - 'DIR': ['projectUuids', 'moduleUuids', 'directories'], - 'DEV': ['authors'], - 'DEV_PRJ': ['projectUuids', 'authors'] - }; -}; - -App.updateContextFacets = function () { - const facets = this.state.get('facets'); - const allFacets = this.state.get('allFacets'); - const facetsFromServer = this.state.get('facetsFromServer'); - return this.state.set({ - facets, - allFacets: _.difference(allFacets, this.getRestrictedFacets()[this.config.resourceQualifier]), - facetsFromServer: _.difference(facetsFromServer, this.getRestrictedFacets()[this.config.resourceQualifier]) - }); -}; - -App.on('start', function (options) { - init.call(App, options); -}); - -window.sonarqube.appStarted.then(options => App.start(options)); diff --git a/server/sonar-web/src/main/js/apps/component-issues/components/ComponentIssuesAppContainer.js b/server/sonar-web/src/main/js/apps/component-issues/components/ComponentIssuesAppContainer.js new file mode 100644 index 00000000000..430ba7b0e79 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-issues/components/ComponentIssuesAppContainer.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import init from '../init'; + +export default class ComponentIssuesAppContainer extends React.Component { + componentDidMount () { + init(this.refs.container); + } + + render () { + return
    ; + } +} diff --git a/server/sonar-web/src/main/js/apps/component-issues/init.js b/server/sonar-web/src/main/js/apps/component-issues/init.js new file mode 100644 index 00000000000..95269406d71 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-issues/init.js @@ -0,0 +1,118 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 $ from 'jquery'; +import _ from 'underscore'; +import Backbone from 'backbone'; +import Marionette from 'backbone.marionette'; +import State from '../issues/models/state'; +import Layout from '../issues/layout'; +import Issues from '../issues/models/issues'; +import Facets from '../../components/navigator/models/facets'; +import Controller from '../issues/controller'; +import Router from '../issues/router'; +import WorkspaceListView from '../issues/workspace-list-view'; +import WorkspaceHeaderView from '../issues/workspace-header-view'; +import FacetsView from './../issues/facets-view'; +import HeaderView from './../issues/HeaderView'; + +const App = new Marionette.Application(); +const init = function (el) { + const options = window.sonarqube; + + this.config = options.config; + this.state = new State({ + canBulkChange: !!window.SS.user, + isContext: true, + contextQuery: { componentUuids: options.config.resource }, + contextComponentUuid: options.config.resource, + contextComponentName: options.config.resourceName, + contextComponentQualifier: options.config.resourceQualifier + }); + this.updateContextFacets(); + this.list = new Issues(); + this.facets = new Facets(); + + this.layout = new Layout({ app: this, el }); + this.layout.render(); + $('#footer').addClass('search-navigator-footer'); + + this.controller = new Controller({ app: this }); + + this.issuesView = new WorkspaceListView({ + app: this, + collection: this.list + }); + this.layout.workspaceListRegion.show(this.issuesView); + this.issuesView.bindScrollEvents(); + + this.workspaceHeaderView = new WorkspaceHeaderView({ + app: this, + collection: this.list + }); + this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView); + + this.facetsView = new FacetsView({ + app: this, + collection: this.facets + }); + this.layout.facetsRegion.show(this.facetsView); + + this.headerView = new HeaderView({ + app: this + }); + this.layout.filtersRegion.show(this.headerView); + + key.setScope('list'); + App.router = new Router({ app: App }); + Backbone.history.start(); +}; + +App.getContextQuery = function () { + return { componentUuids: this.config.resource }; +}; + +App.getRestrictedFacets = function () { + return { + 'TRK': ['projectUuids'], + 'BRC': ['projectUuids'], + 'DIR': ['projectUuids', 'moduleUuids', 'directories'], + 'DEV': ['authors'], + 'DEV_PRJ': ['projectUuids', 'authors'] + }; +}; + +App.updateContextFacets = function () { + const facets = this.state.get('facets'); + const allFacets = this.state.get('allFacets'); + const facetsFromServer = this.state.get('facetsFromServer'); + return this.state.set({ + facets, + allFacets: _.difference(allFacets, this.getRestrictedFacets()[this.config.resourceQualifier]), + facetsFromServer: _.difference(facetsFromServer, this.getRestrictedFacets()[this.config.resourceQualifier]) + }); +}; + +App.on('start', function (el) { + init.call(App, el); +}); + +export default function (el) { + App.start(el); +} diff --git a/server/sonar-web/src/main/js/apps/component-issues/routes.js b/server/sonar-web/src/main/js/apps/component-issues/routes.js new file mode 100644 index 00000000000..e07322509f2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-issues/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import ComponentIssuesAppContainer from './components/ComponentIssuesAppContainer'; + +export default ( + +); diff --git a/server/sonar-web/src/main/js/apps/component-measures/app.js b/server/sonar-web/src/main/js/apps/component-measures/app.js deleted file mode 100644 index 230a10f092a..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/app.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { render } from 'react-dom'; -import { Router, Route, IndexRoute, Redirect, IndexRedirect, useRouterHistory } from 'react-router'; -import { createHistory } from 'history'; -import { Provider } from 'react-redux'; - -import AppContainer from './app/AppContainer'; -import HomeContainer from './home/HomeContainer'; -import AllMeasuresContainer from './home/AllMeasuresContainer'; -import DomainMeasuresContainer from './home/DomainMeasuresContainer'; -import MeasureDetailsContainer from './details/MeasureDetailsContainer'; -import ListViewContainer from './details/drilldown/ListViewContainer'; -import TreeViewContainer from './details/drilldown/TreeViewContainer'; -import MeasureHistoryContainer from './details/history/MeasureHistoryContainer'; -import MeasureTreemapContainer from './details/treemap/MeasureTreemapContainer'; - -import configureStore from './store/configureStore'; - -import { checkHistoryExistence } from './hooks'; - -import './styles.css'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - - const history = useRouterHistory(createHistory)({ - basename: window.baseUrl + '/component_measures' - }); - - const store = configureStore({ - app: { component: options.component } - }); - - const handleRouteUpdate = () => { - window.scrollTo(0, 0); - }; - - render(( - - - - - - - - - - - - - - - - - - - - - - - ), el); -}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/app/App.js b/server/sonar-web/src/main/js/apps/component-measures/app/App.js index fa23544cd91..75fa2d320a4 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/app/App.js +++ b/server/sonar-web/src/main/js/apps/component-measures/app/App.js @@ -23,6 +23,7 @@ import Spinner from './../components/Spinner'; export default class App extends React.Component { componentDidMount () { + this.props.setComponent(this.props.component); this.props.fetchMetrics(); } diff --git a/server/sonar-web/src/main/js/apps/component-measures/app/AppContainer.js b/server/sonar-web/src/main/js/apps/component-measures/app/AppContainer.js index 2bd53a0ab19..c3e9e632d10 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/app/AppContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/app/AppContainer.js @@ -18,19 +18,20 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; - import App from './App'; -import { fetchMetrics } from './actions'; +import { fetchMetrics, setComponent } from './actions'; +import { getMeasuresAppAllMetrics } from '../../../app/store/rootReducer'; const mapStateToProps = state => { return { - metrics: state.app.metrics + metrics: getMeasuresAppAllMetrics(state) }; }; const mapDispatchToProps = dispatch => { return { - fetchMetrics: () => dispatch(fetchMetrics()) + fetchMetrics: () => dispatch(fetchMetrics()), + setComponent: component => dispatch(setComponent(component)) }; }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/app/actions.js b/server/sonar-web/src/main/js/apps/component-measures/app/actions.js index 85f74ffa9a4..92e80e68fc1 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/app/actions.js +++ b/server/sonar-web/src/main/js/apps/component-measures/app/actions.js @@ -23,8 +23,9 @@ import { getMetrics } from '../../../api/metrics'; * Actions */ -export const DISPLAY_HOME = 'app/DISPLAY_HOME'; -export const RECEIVE_METRICS = 'app/RECEIVE_METRICS'; +export const DISPLAY_HOME = 'measuresApp/app/DISPLAY_HOME'; +export const RECEIVE_METRICS = 'measuresApp/app/RECEIVE_METRICS'; +export const SET_COMPONENT = 'measuresApp/app/SET_COMPONENT'; /* * Action Creators @@ -38,6 +39,10 @@ function receiveMetrics (metrics) { return { type: RECEIVE_METRICS, metrics }; } +export function setComponent (component) { + return { type: SET_COMPONENT, component }; +} + /* * Workflow */ diff --git a/server/sonar-web/src/main/js/apps/component-measures/app/reducer.js b/server/sonar-web/src/main/js/apps/component-measures/app/reducer.js index 2484e2d0563..0df67b1d78f 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/app/reducer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/app/reducer.js @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { RECEIVE_METRICS } from './actions'; +import { RECEIVE_METRICS, SET_COMPONENT } from './actions'; const initialState = { metrics: undefined @@ -27,6 +27,8 @@ export default function appReducer (state = initialState, action = {}) { switch (action.type) { case RECEIVE_METRICS: return { ...state, metrics: action.metrics }; + case SET_COMPONENT: + return { ...state, component: action.component }; default: return state; } diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/MeasureBubbleChartContainer.js b/server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/MeasureBubbleChartContainer.js index f219bfe01cc..029cee95b55 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/MeasureBubbleChartContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/MeasureBubbleChartContainer.js @@ -18,13 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; - import MeasureBubbleChart from './BubbleChart'; +import { getMeasuresAppAllMetrics, getMeasuresAppComponent } from '../../../../app/store/rootReducer'; const mapStateToProps = state => { return { - component: state.app.component, - metrics: state.app.metrics + component: getMeasuresAppComponent(state), + metrics: getMeasuresAppAllMetrics(state) }; }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetails.js b/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetails.js index 35d400d3e4c..125b9c72897 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetails.js +++ b/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetails.js @@ -71,7 +71,7 @@ export default class MeasureDetails extends React.Component {
    {translate('component_measures.all_measures')} @@ -80,7 +80,7 @@ export default class MeasureDetails extends React.Component { {' / '} {translateWithParameters('component_measures.domain_measures', metric.domain)} diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsContainer.js b/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsContainer.js index b0d87963394..055ce5225e3 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsContainer.js @@ -18,18 +18,25 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; - import MeasureDetails from './MeasureDetails'; import { fetchMeasure } from './actions'; +import { + getMeasuresAppAllMetrics, + getMeasuresAppDetailsMetric, + getMeasuresAppDetailsMeasure, + getMeasuresAppDetailsSecondaryMeasure, + getMeasuresAppDetailsPeriods + , getMeasuresAppComponent +} from '../../../app/store/rootReducer'; const mapStateToProps = state => { return { - component: state.app.component, - metrics: state.app.metrics, - metric: state.details.metric, - measure: state.details.measure, - secondaryMeasure: state.details.secondaryMeasure, - periods: state.details.periods + component: getMeasuresAppComponent(state), + metrics: getMeasuresAppAllMetrics(state), + metric: getMeasuresAppDetailsMetric(state), + measure: getMeasuresAppDetailsMeasure(state), + secondaryMeasure: getMeasuresAppDetailsSecondaryMeasure(state), + periods: getMeasuresAppDetailsPeriods(state) }; }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/actions.js b/server/sonar-web/src/main/js/apps/component-measures/details/actions.js index 7f24fce6112..608c7e2b97c 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/details/actions.js +++ b/server/sonar-web/src/main/js/apps/component-measures/details/actions.js @@ -19,13 +19,14 @@ */ import { getMeasuresAndMeta } from '../../../api/measures'; import { enhanceWithLeak } from '../utils'; +import { getMeasuresAppComponent, getMeasuresAppAllMetrics } from '../../../app/store/rootReducer'; /* * Actions */ -export const REQUEST_MEASURE = 'details/REQUEST_MEASURE'; -export const RECEIVE_MEASURE = 'details/RECEIVE_MEASURE'; +export const REQUEST_MEASURE = 'measuresApp/details/REQUEST_MEASURE'; +export const RECEIVE_MEASURE = 'measuresApp/details/RECEIVE_MEASURE'; /* * Action Creators @@ -45,7 +46,9 @@ function receiveMeasure (measure, secondaryMeasure, periods) { export function fetchMeasure (metricKey, periodIndex = 1) { return (dispatch, getState) => { - const { component, metrics } = getState().app; + const state = getState(); + const component = getMeasuresAppComponent(state); + const metrics = getMeasuresAppAllMetrics(state); const metricsToRequest = [metricKey]; if (metricKey === 'ncloc') { diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListViewContainer.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListViewContainer.js index c96c5586383..d982d7aef88 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListViewContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListViewContainer.js @@ -18,24 +18,29 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; -import pick from '../../../../../../../node_modules/lodash/pick'; - import ListView from './ListView'; import { fetchList, fetchMore, selectComponent, selectNext, selectPrevious } from '../../store/listViewActions'; +import { + getMeasuresAppListComponents, + getMeasuresAppListSelected, + getMeasuresAppListTotal, + getMeasuresAppListPageIndex, + getMeasuresAppAllMetrics, + getMeasuresAppDetailsMetric, + isMeasuresAppFetching + , getMeasuresAppComponent +} from '../../../../app/store/rootReducer'; const mapStateToProps = state => { - const drilldown = pick(state.list, [ - 'components', - 'selected', - 'total', - 'pageIndex' - ]); return { - ...drilldown, - component: state.app.component, - metrics: state.app.metrics, - metric: state.details.metric, - fetching: state.status.fetching + components: getMeasuresAppListComponents(state), + selected: getMeasuresAppListSelected(state), + total: getMeasuresAppListTotal(state), + pageIndex: getMeasuresAppListPageIndex(state), + component: getMeasuresAppComponent(state), + metrics: getMeasuresAppAllMetrics(state), + metric: getMeasuresAppDetailsMetric(state), + fetching: isMeasuresAppFetching(state) }; }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureDrilldown.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureDrilldown.js index f41d19f8411..cc7e06546ed 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureDrilldown.js +++ b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureDrilldown.js @@ -39,20 +39,20 @@ export default class MeasureDrilldown extends React.Component {
      {component.qualifier !== 'DEV' && ( -
    • - - - {translate('component_measures.tab.list')} - -
    • +
    • + + + {translate('component_measures.tab.list')} + +
    • )}
    • + to={{ pathname: `/component_measures/metric/${metric.key}/tree`, query: { id: component.key } }}> {translate('component_measures.tab.tree')} @@ -62,7 +62,10 @@ export default class MeasureDrilldown extends React.Component {
    • + to={{ + pathname: `/component_measures/metric/${metric.key}/bubbles`, + query: { id: component.key } + }}> {translate('component_measures.tab.bubbles')} @@ -73,7 +76,10 @@ export default class MeasureDrilldown extends React.Component {
    • + to={{ + pathname: `/component_measures/metric/${metric.key}/treemap`, + query: { id: component.key } + }}> {translate('component_measures.tab.treemap')} @@ -84,7 +90,10 @@ export default class MeasureDrilldown extends React.Component {
    • + to={{ + pathname: `/component_measures/metric/${metric.key}/history`, + query: { id: component.key } + }}> {translate('component_measures.tab.history')} diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeViewContainer.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeViewContainer.js index 4900542ad24..114b9ef08e2 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeViewContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeViewContainer.js @@ -18,33 +18,39 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; -import pick from '../../../../../../../node_modules/lodash/pick'; - import TreeView from './TreeView'; import { - start, - drilldown, - useBreadcrumbs, - fetchMore, - selectComponent, - selectNext, - selectPrevious + start, + drilldown, + useBreadcrumbs, + fetchMore, + selectComponent, + selectNext, + selectPrevious } from '../../store/treeViewActions'; +import { + getMeasuresAppTreeComponents, + getMeasuresAppTreeBreadcrumbs, + getMeasuresAppTreeSelected, + getMeasuresAppTreeTotal, + getMeasuresAppTreePageIndex, + getMeasuresAppAllMetrics, + getMeasuresAppDetailsMetric, + isMeasuresAppFetching + , getMeasuresAppComponent +} from '../../../../app/store/rootReducer'; const mapStateToProps = state => { - const drilldown = pick(state.tree, [ - 'components', - 'breadcrumbs', - 'selected', - 'total', - 'pageIndex' - ]); return { - ...drilldown, - component: state.app.component, - metrics: state.app.metrics, - metric: state.details.metric, - fetching: state.status.fetching + components: getMeasuresAppTreeComponents(state), + breadcrumbs: getMeasuresAppTreeBreadcrumbs(state), + selected: getMeasuresAppTreeSelected(state), + total: getMeasuresAppTreeTotal(state), + pageIndex: getMeasuresAppTreePageIndex(state), + component: getMeasuresAppComponent(state), + metrics: getMeasuresAppAllMetrics(state), + metric: getMeasuresAppDetailsMetric(state), + fetching: isMeasuresAppFetching(state) }; }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/history/MeasureHistoryContainer.js b/server/sonar-web/src/main/js/apps/component-measures/details/history/MeasureHistoryContainer.js index bfe7decf1a3..b70189eedb5 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/details/history/MeasureHistoryContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/details/history/MeasureHistoryContainer.js @@ -18,13 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; - import MeasureHistory from './MeasureHistory'; +import { getMeasuresAppDetailsMetric, getMeasuresAppComponent } from '../../../../app/store/rootReducer'; const mapStateToProps = state => { return { - component: state.app.component, - metric: state.details.metric + component: getMeasuresAppComponent(state), + metric: getMeasuresAppDetailsMetric(state) }; }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemapContainer.js b/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemapContainer.js index 978a2a522e2..e24858b82e3 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemapContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemapContainer.js @@ -18,13 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; - import MeasureTreemap from './MeasureTreemap'; +import { getMeasuresAppDetailsMetric, getMeasuresAppComponent } from '../../../../app/store/rootReducer'; const mapStateToProps = state => { return { - component: state.app.component, - metric: state.details.metric + component: getMeasuresAppComponent(state), + metric: getMeasuresAppDetailsMetric(state) }; }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresContainer.js b/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresContainer.js index 00bb948b70b..d02d06bfcc3 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresContainer.js @@ -18,14 +18,18 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; - import AllMeasures from './AllMeasures'; +import { + getMeasuresAppHomeDomains, + getMeasuresAppHomePeriods, + getMeasuresAppComponent +} from '../../../app/store/rootReducer'; const mapStateToProps = state => { return { - component: state.app.component, - domains: state.home.domains, - periods: state.home.periods + component: getMeasuresAppComponent(state), + domains: getMeasuresAppHomeDomains(state), + periods: getMeasuresAppHomePeriods(state) }; }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasuresContainer.js b/server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasuresContainer.js index f71d24c0368..53094eb9bc7 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasuresContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasuresContainer.js @@ -18,14 +18,18 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; - import DomainMeasures from './DomainMeasures'; +import { + getMeasuresAppHomeDomains, + getMeasuresAppHomePeriods, + getMeasuresAppComponent +} from '../../../app/store/rootReducer'; const mapStateToProps = state => { return { - component: state.app.component, - domains: state.home.domains, - periods: state.home.periods + component: getMeasuresAppComponent(state), + domains: getMeasuresAppHomeDomains(state), + periods: getMeasuresAppHomePeriods(state) }; }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/Home.js b/server/sonar-web/src/main/js/apps/component-measures/home/Home.js index 84b8dabece3..6b1faf5402f 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/home/Home.js +++ b/server/sonar-web/src/main/js/apps/component-measures/home/Home.js @@ -51,7 +51,7 @@ export default class Home extends React.Component {
      • {translate('all')} @@ -59,7 +59,7 @@ export default class Home extends React.Component { {domains.map(domain => (
      • {getLocalizedMetricDomain(domain.name)} diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/HomeContainer.js b/server/sonar-web/src/main/js/apps/component-measures/home/HomeContainer.js index a5473ec3dba..58e3285c181 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/home/HomeContainer.js +++ b/server/sonar-web/src/main/js/apps/component-measures/home/HomeContainer.js @@ -18,16 +18,20 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { connect } from 'react-redux'; - import Home from './Home'; import { fetchMeasures } from './actions'; import { displayHome } from '../app/actions'; +import { + getMeasuresAppHomeDomains, + getMeasuresAppHomePeriods, + getMeasuresAppComponent +} from '../../../app/store/rootReducer'; const mapStateToProps = state => { return { - component: state.app.component, - domains: state.home.domains, - periods: state.home.periods + component: getMeasuresAppComponent(state), + domains: getMeasuresAppHomeDomains(state), + periods: getMeasuresAppHomePeriods(state) }; }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/MeasuresList.js b/server/sonar-web/src/main/js/apps/component-measures/home/MeasuresList.js index 95a0ac857a8..42d3f46e94f 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/home/MeasuresList.js +++ b/server/sonar-web/src/main/js/apps/component-measures/home/MeasuresList.js @@ -30,7 +30,7 @@ const MeasuresList = ({ measures, component, className = 'domain-measures' }) =>
      • - +
        {getLocalizedMetricName(measure.metric)} diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/actions.js b/server/sonar-web/src/main/js/apps/component-measures/home/actions.js index 31a9309c900..006d4680523 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/home/actions.js +++ b/server/sonar-web/src/main/js/apps/component-measures/home/actions.js @@ -21,8 +21,9 @@ import { startFetching, stopFetching } from '../store/statusActions'; import { getMeasuresAndMeta } from '../../../api/measures'; import { getLeakPeriod } from '../../../helpers/periods'; import { getLeakValue } from '../utils'; +import { getMeasuresAppComponent, getMeasuresAppAllMetrics } from '../../../app/store/rootReducer'; -export const RECEIVE_MEASURES = 'home/RECEIVE_MEASURES'; +export const RECEIVE_MEASURES = 'measuresApp/home/RECEIVE_MEASURES'; export function receiveMeasures (measures, periods) { return { type: RECEIVE_MEASURES, measures, periods }; @@ -39,7 +40,10 @@ export function fetchMeasures () { return (dispatch, getState) => { dispatch(startFetching()); - const { component, metrics } = getState().app; + const state = getState(); + const component = getMeasuresAppComponent(state); + const metrics = getMeasuresAppAllMetrics(state); + const metricKeys = metrics .filter(metric => !metric.hidden) .filter(metric => metric.type !== 'DATA' && metric.type !== 'DISTRIB') diff --git a/server/sonar-web/src/main/js/apps/component-measures/routes.js b/server/sonar-web/src/main/js/apps/component-measures/routes.js new file mode 100644 index 00000000000..e2e24f96034 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/routes.js @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { Route, IndexRoute, IndexRedirect } from 'react-router'; +import AppContainer from './app/AppContainer'; +import HomeContainer from './home/HomeContainer'; +import AllMeasuresContainer from './home/AllMeasuresContainer'; +import DomainMeasuresContainer from './home/DomainMeasuresContainer'; +import MeasureDetailsContainer from './details/MeasureDetailsContainer'; +import ListViewContainer from './details/drilldown/ListViewContainer'; +import TreeViewContainer from './details/drilldown/TreeViewContainer'; +import MeasureHistoryContainer from './details/history/MeasureHistoryContainer'; +import MeasureTreemapContainer from './details/treemap/MeasureTreemapContainer'; +import { checkHistoryExistence } from './hooks'; +import './styles.css'; + +export default ( + + + + + + + + + + + + + + +); diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/configureStore.js b/server/sonar-web/src/main/js/apps/component-measures/store/configureStore.js deleted file mode 100644 index 07d55655531..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/store/configureStore.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 appReducer from './../app/reducer'; -import statusReducer from './statusReducer'; -import homeReducer from '../home/reducer'; -import detailsReducer from '../details/reducer'; -import listViewReducer from './listViewReducer'; -import treeViewReducer from './treeViewReducer'; -import configureStore from '../../../components/store/configureStore'; - -export default function customConfigureStore (initialState) { - const rootReducer = combineReducers({ - app: appReducer, - home: homeReducer, - details: detailsReducer, - list: listViewReducer, - tree: treeViewReducer, - status: statusReducer - }); - - return configureStore(rootReducer, initialState); -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/listViewActions.js b/server/sonar-web/src/main/js/apps/component-measures/store/listViewActions.js index 8e61e53dd0a..1f48656bfb8 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/store/listViewActions.js +++ b/server/sonar-web/src/main/js/apps/component-measures/store/listViewActions.js @@ -21,8 +21,9 @@ import { getComponentTree } from '../../../api/components'; import { enhanceWithMeasure } from '../utils'; import { startFetching, stopFetching } from './statusActions'; import complementary from '../config/complementary'; +import { getMeasuresAppList } from '../../../app/store/rootReducer'; -export const UPDATE_STORE = 'drilldown/list/UPDATE_STORE'; +export const UPDATE_STORE = 'measuresApp/drilldown/list/UPDATE_STORE'; function updateStore (state) { return { type: UPDATE_STORE, state }; @@ -77,7 +78,7 @@ function fetchLeaves (baseComponent, metric, pageIndex = 1, periodIndex = 1) { */ export function fetchList (baseComponent, metric, periodIndex = 1) { return (dispatch, getState) => { - const { list } = getState(); + const list = getMeasuresAppList(getState()); if (list.baseComponent === baseComponent && list.metric === metric) { return Promise.resolve(); } @@ -96,7 +97,7 @@ export function fetchList (baseComponent, metric, periodIndex = 1) { export function fetchMore (periodIndex) { return (dispatch, getState) => { - const { baseComponent, metric, pageIndex, components } = getState().list; + const { baseComponent, metric, pageIndex, components } = getMeasuresAppList(getState()); dispatch(startFetching()); return fetchLeaves(baseComponent, metric, pageIndex + 1, periodIndex).then(r => { const nextComponents = [...components, ...r.components]; @@ -121,7 +122,7 @@ export function selectComponent (component) { */ export function selectNext () { return (dispatch, getState) => { - const { components, selected } = getState().list; + const { components, selected } = getMeasuresAppList(getState()); const selectedIndex = components.indexOf(selected); if (selectedIndex < components.length - 1) { const nextSelected = components[selectedIndex + 1]; @@ -135,7 +136,7 @@ export function selectNext () { */ export function selectPrevious () { return (dispatch, getState) => { - const { components, selected } = getState().list; + const { components, selected } = getMeasuresAppList(getState()); const selectedIndex = components.indexOf(selected); if (selectedIndex > 0) { const nextSelected = components[selectedIndex - 1]; diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/rootReducer.js b/server/sonar-web/src/main/js/apps/component-measures/store/rootReducer.js new file mode 100644 index 00000000000..f57fef25a4a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/store/rootReducer.js @@ -0,0 +1,116 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 appReducer from './../app/reducer'; +import statusReducer from './statusReducer'; +import homeReducer from '../home/reducer'; +import detailsReducer from '../details/reducer'; +import listViewReducer from './listViewReducer'; +import treeViewReducer from './treeViewReducer'; + +export default combineReducers({ + app: appReducer, + home: homeReducer, + details: detailsReducer, + list: listViewReducer, + tree: treeViewReducer, + status: statusReducer +}); + +export const getComponent = state => ( + state.app.component +); + +export const getAllMetrics = state => ( + state.app.metrics +); + +export const getDetailsMetric = state => ( + state.details.metric +); + +export const getDetailsMeasure = state => ( + state.details.measure +); + +export const getDetailsSecondaryMeasure = state => ( + state.details.secondaryMeasure +); + +export const getDetailsPeriods = state => ( + state.details.periods +); + +export const isFetching = state => ( + state.status.fetching +); + +export const getList = state => ( + state.list +); + +export const getListComponents = state => ( + state.list.components +); + +export const getListSelected = state => ( + state.list.selected +); + +export const getListTotal = state => ( + state.list.total +); + +export const getListPageIndex = state => ( + state.list.pageIndex +); + +export const getTree = state => ( + state.tree +); + +export const getTreeComponents = state => ( + state.tree.components +); + +export const getTreeBreadcrumbs = state => ( + state.tree.breadcrumbs +); + +export const getTreeSelected = state => ( + state.tree.selected +); + +export const getTreeTotal = state => ( + state.tree.total +); + +export const getTreePageIndex = state => ( + state.tree.pageIndex +); + +export const getHomeDomains = state => ( + state.home.domains +); + +export const getHomePeriods = state => ( + state.home.periods +); diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/statusActions.js b/server/sonar-web/src/main/js/apps/component-measures/store/statusActions.js index 5755ad5ff55..83eb605cb7c 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/store/statusActions.js +++ b/server/sonar-web/src/main/js/apps/component-measures/store/statusActions.js @@ -17,8 +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 START_FETCHING = 'status/START_FETCHING'; -export const STOP_FETCHING = 'status/STOP_FETCHING'; +export const START_FETCHING = 'measuresApp/status/START_FETCHING'; +export const STOP_FETCHING = 'measuresApp/status/STOP_FETCHING'; export function startFetching () { return { type: START_FETCHING }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/treeViewActions.js b/server/sonar-web/src/main/js/apps/component-measures/store/treeViewActions.js index 49cc3ff504d..81d2896c9d8 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/store/treeViewActions.js +++ b/server/sonar-web/src/main/js/apps/component-measures/store/treeViewActions.js @@ -23,13 +23,14 @@ import { getComponentTree } from '../../../api/components'; import { enhanceWithMeasure } from '../utils'; import { startFetching, stopFetching } from './statusActions'; import complementary from '../config/complementary'; +import { getMeasuresAppTree } from '../../../app/store/rootReducer'; /* * Actions */ -export const UPDATE_STORE = 'drilldown/tree/UPDATE_STORE'; -export const INIT = 'drilldown/tree/INIT'; +export const UPDATE_STORE = 'measuresApp/drilldown/tree/UPDATE_STORE'; +export const INIT = 'measuresApp/drilldown/tree/INIT'; /* * Action Creators @@ -115,7 +116,7 @@ function fetchComponents (rootComponent, baseComponent, metric, pageIndex = 1, p */ function fetchList (baseComponent) { return (dispatch, getState) => { - const { metric, periodIndex, rootComponent } = getState().tree; + const { metric, periodIndex, rootComponent } = getMeasuresAppTree(getState()); dispatch(startFetching()); return fetchComponents(rootComponent, baseComponent, metric, 1, periodIndex).then(r => { @@ -139,7 +140,7 @@ function fetchList (baseComponent) { */ export function start (rootComponent, metric, periodIndex = 1) { return (dispatch, getState) => { - const { tree } = getState(); + const tree = getMeasuresAppTree(getState()); if (rootComponent === tree.rootComponent && metric === tree.metric) { return Promise.resolve(); } @@ -155,7 +156,7 @@ export function start (rootComponent, metric, periodIndex = 1) { */ export function drilldown (component) { return (dispatch, getState) => { - const { metric, rootComponent, breadcrumbs, periodIndex } = getState().tree; + const { metric, rootComponent, breadcrumbs, periodIndex } = getMeasuresAppTree(getState()); dispatch(startFetching()); return fetchComponents(rootComponent, component, metric, 1, periodIndex).then(r => { dispatch(updateStore({ @@ -174,7 +175,7 @@ export function drilldown (component) { */ export function useBreadcrumbs (component) { return (dispatch, getState) => { - const { metric, rootComponent, breadcrumbs, periodIndex } = getState().tree; + const { metric, rootComponent, breadcrumbs, periodIndex } = getMeasuresAppTree(getState()); const index = breadcrumbs.indexOf(component); dispatch(startFetching()); return fetchComponents(rootComponent, component, metric, 1, periodIndex).then(r => { @@ -190,7 +191,7 @@ export function useBreadcrumbs (component) { export function fetchMore () { return (dispatch, getState) => { - const { rootComponent, baseComponent, metric, pageIndex, components, periodIndex } = getState().tree; + const { rootComponent, baseComponent, metric, pageIndex, components, periodIndex } = getMeasuresAppTree(getState()); dispatch(startFetching()); return fetchComponents(rootComponent, baseComponent, metric, pageIndex + 1, periodIndex).then(r => { const nextComponents = [...components, ...r.components]; @@ -206,7 +207,7 @@ export function fetchMore () { */ export function selectComponent (component) { return (dispatch, getState) => { - const { breadcrumbs } = getState().tree; + const { breadcrumbs } = getMeasuresAppTree(getState()); const nextBreadcrumbs = [...breadcrumbs, component]; dispatch(updateStore({ selected: component, @@ -220,7 +221,7 @@ export function selectComponent (component) { */ export function selectNext () { return (dispatch, getState) => { - const { components, selected, breadcrumbs } = getState().tree; + const { components, selected, breadcrumbs } = getMeasuresAppTree(getState()); const selectedIndex = components.indexOf(selected); if (selectedIndex < components.length - 1) { const nextSelected = components[selectedIndex + 1]; @@ -238,7 +239,7 @@ export function selectNext () { */ export function selectPrevious () { return (dispatch, getState) => { - const { components, selected, breadcrumbs } = getState().tree; + const { components, selected, breadcrumbs } = getMeasuresAppTree(getState()); const selectedIndex = components.indexOf(selected); if (selectedIndex > 0) { const nextSelected = components[selectedIndex - 1]; diff --git a/server/sonar-web/src/main/js/apps/custom-measures/app.js b/server/sonar-web/src/main/js/apps/custom-measures/app.js deleted file mode 100644 index 531584e81d4..00000000000 --- a/server/sonar-web/src/main/js/apps/custom-measures/app.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 Marionette from 'backbone.marionette'; -import Layout from './layout'; -import CustomMeasures from './custom-measures'; -import HeaderView from './header-view'; -import ListView from './list-view'; -import ListFooterView from './list-footer-view'; - -const App = new Marionette.Application(); -const init = function (options) { - // Layout - this.layout = new Layout({ - el: options.el - }); - this.layout.render(); - - // Collection - this.customMeasures = new CustomMeasures({ - projectId: options.component.id - }); - - // Header View - this.headerView = new HeaderView({ - collection: this.customMeasures, - projectId: options.component.id - }); - this.layout.headerRegion.show(this.headerView); - - // List View - this.listView = new ListView({ - collection: this.customMeasures - }); - this.layout.listRegion.show(this.listView); - - // List Footer View - this.listFooterView = new ListFooterView({ - collection: this.customMeasures - }); - this.layout.listFooterRegion.show(this.listFooterView); - - // Go! - this.customMeasures.fetch(); -}; - -App.on('start', function (options) { - init.call(App, options); -}); - -window.sonarqube.appStarted.then(options => App.start(options)); - diff --git a/server/sonar-web/src/main/js/apps/custom-measures/components/CustomMeasuresAppContainer.js b/server/sonar-web/src/main/js/apps/custom-measures/components/CustomMeasuresAppContainer.js new file mode 100644 index 00000000000..a88477e394a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/components/CustomMeasuresAppContainer.js @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import init from '../init'; + +export default class CustomMeasuresAppContainer extends React.Component { + componentDidMount () { + if (this.props.component) { + init(this.refs.container, this.props.component); + } + } + + componentDidUpdate () { + if (this.props.component) { + init(this.refs.container, this.props.component); + } + } + + render () { + return
        ; + } +} diff --git a/server/sonar-web/src/main/js/apps/custom-measures/init.js b/server/sonar-web/src/main/js/apps/custom-measures/init.js new file mode 100644 index 00000000000..caf512737a0 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/init.js @@ -0,0 +1,68 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 Marionette from 'backbone.marionette'; +import Layout from './layout'; +import CustomMeasures from './custom-measures'; +import HeaderView from './header-view'; +import ListView from './list-view'; +import ListFooterView from './list-footer-view'; + +const App = new Marionette.Application(); +const init = function (el, component) { + // Layout + this.layout = new Layout({ el }); + this.layout.render(); + + // Collection + this.customMeasures = new CustomMeasures({ + projectId: component.id + }); + + // Header View + this.headerView = new HeaderView({ + collection: this.customMeasures, + projectId: component.id + }); + this.layout.headerRegion.show(this.headerView); + + // List View + this.listView = new ListView({ + collection: this.customMeasures + }); + this.layout.listRegion.show(this.listView); + + // List Footer View + this.listFooterView = new ListFooterView({ + collection: this.customMeasures + }); + this.layout.listFooterRegion.show(this.listFooterView); + + // Go! + this.customMeasures.fetch(); +}; + +App.on('start', function (options) { + init.call(App, options.el, options.component); +}); + +export default function (el, component) { + App.start({ el, component }); +} + diff --git a/server/sonar-web/src/main/js/apps/custom-measures/routes.js b/server/sonar-web/src/main/js/apps/custom-measures/routes.js new file mode 100644 index 00000000000..09b916d711d --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import CustomMeasuresAppContainer from './components/CustomMeasuresAppContainer'; + +export default ( + +); diff --git a/server/sonar-web/src/main/js/apps/groups/app.js b/server/sonar-web/src/main/js/apps/groups/app.js deleted file mode 100644 index c9d8562646f..00000000000 --- a/server/sonar-web/src/main/js/apps/groups/app.js +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 Marionette from 'backbone.marionette'; -import Layout from './layout'; -import Groups from './groups'; -import HeaderView from './header-view'; -import SearchView from './search-view'; -import ListView from './list-view'; -import ListFooterView from './list-footer-view'; - -const App = new Marionette.Application(); -const init = function () { - const options = window.sonarqube; - - // Layout - this.layout = new Layout({ el: options.el }); - this.layout.render(); - - // Collection - this.groups = new Groups(); - - // Header View - this.headerView = new HeaderView({ collection: this.groups }); - this.layout.headerRegion.show(this.headerView); - - // Search View - this.searchView = new SearchView({ collection: this.groups }); - this.layout.searchRegion.show(this.searchView); - - // List View - this.listView = new ListView({ collection: this.groups }); - this.layout.listRegion.show(this.listView); - - // List Footer View - this.listFooterView = new ListFooterView({ collection: this.groups }); - this.layout.listFooterRegion.show(this.listFooterView); - - // Go! - this.groups.fetch(); -}; - -App.on('start', function () { - init.call(App); -}); - -window.sonarqube.appStarted.then(options => App.start(options)); - diff --git a/server/sonar-web/src/main/js/apps/groups/components/GroupsAppContainer.js b/server/sonar-web/src/main/js/apps/groups/components/GroupsAppContainer.js new file mode 100644 index 00000000000..55cbb49127e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/groups/components/GroupsAppContainer.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import init from '../init'; + +export default class GroupsAppContainer extends React.Component { + componentDidMount () { + init(this.refs.container); + } + + render () { + return
        ; + } +} diff --git a/server/sonar-web/src/main/js/apps/groups/init.js b/server/sonar-web/src/main/js/apps/groups/init.js new file mode 100644 index 00000000000..4ec6a7e95e6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/groups/init.js @@ -0,0 +1,64 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 Marionette from 'backbone.marionette'; +import Layout from './layout'; +import Groups from './groups'; +import HeaderView from './header-view'; +import SearchView from './search-view'; +import ListView from './list-view'; +import ListFooterView from './list-footer-view'; + +const App = new Marionette.Application(); +const init = function (el) { + // Layout + this.layout = new Layout({ el }); + this.layout.render(); + + // Collection + this.groups = new Groups(); + + // Header View + this.headerView = new HeaderView({ collection: this.groups }); + this.layout.headerRegion.show(this.headerView); + + // Search View + this.searchView = new SearchView({ collection: this.groups }); + this.layout.searchRegion.show(this.searchView); + + // List View + this.listView = new ListView({ collection: this.groups }); + this.layout.listRegion.show(this.listView); + + // List Footer View + this.listFooterView = new ListFooterView({ collection: this.groups }); + this.layout.listFooterRegion.show(this.listFooterView); + + // Go! + this.groups.fetch(); +}; + +App.on('start', function (el) { + init.call(App, el); +}); + +export default function (el) { + App.start(el); +} + diff --git a/server/sonar-web/src/main/js/apps/groups/routes.js b/server/sonar-web/src/main/js/apps/groups/routes.js new file mode 100644 index 00000000000..08981267c79 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/groups/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import GroupsAppContainer from './components/GroupsAppContainer'; + +export default ( + +); diff --git a/server/sonar-web/src/main/js/apps/issues/app.js b/server/sonar-web/src/main/js/apps/issues/app.js deleted file mode 100644 index 4623b55988f..00000000000 --- a/server/sonar-web/src/main/js/apps/issues/app.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 $ from 'jquery'; -import Backbone from 'backbone'; -import Marionette from 'backbone.marionette'; -import State from './models/state'; -import Layout from './layout'; -import Issues from './models/issues'; -import Facets from '../../components/navigator/models/facets'; -import Controller from './controller'; -import Router from './router'; -import WorkspaceListView from './workspace-list-view'; -import WorkspaceHeaderView from './workspace-header-view'; -import FacetsView from './facets-view'; -import HeaderView from './HeaderView'; - -const App = new Marionette.Application(); -const init = function () { - const options = window.sonarqube; - - this.state = new State({ canBulkChange: !!window.SS.user }); - this.list = new Issues(); - this.facets = new Facets(); - - this.layout = new Layout({ app: this, el: options.el }); - this.layout.render(); - $('#footer').addClass('search-navigator-footer'); - - this.controller = new Controller({ app: this }); - - this.issuesView = new WorkspaceListView({ - app: this, - collection: this.list - }); - this.layout.workspaceListRegion.show(this.issuesView); - this.issuesView.bindScrollEvents(); - - this.workspaceHeaderView = new WorkspaceHeaderView({ - app: this, - collection: this.list - }); - this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView); - - this.facetsView = new FacetsView({ - app: this, - collection: this.facets - }); - this.layout.facetsRegion.show(this.facetsView); - - this.headerView = new HeaderView({ - app: this - }); - this.layout.filtersRegion.show(this.headerView); - - key.setScope('list'); - App.router = new Router({ app: App }); - Backbone.history.start(); -}; - -App.on('start', function () { - init.call(App); -}); - -window.sonarqube.appStarted.then(options => App.start(options)); - diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssuesAppContainer.js b/server/sonar-web/src/main/js/apps/issues/components/IssuesAppContainer.js new file mode 100644 index 00000000000..33820285418 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/components/IssuesAppContainer.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import init from '../init'; + +export default class IssuesAppContainer extends React.Component { + componentDidMount () { + init(this.refs.container); + } + + render () { + return
        ; + } +} diff --git a/server/sonar-web/src/main/js/apps/issues/init.js b/server/sonar-web/src/main/js/apps/issues/init.js new file mode 100644 index 00000000000..2ac5041b6ef --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/init.js @@ -0,0 +1,82 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 $ from 'jquery'; +import Backbone from 'backbone'; +import Marionette from 'backbone.marionette'; +import State from './models/state'; +import Layout from './layout'; +import Issues from './models/issues'; +import Facets from '../../components/navigator/models/facets'; +import Controller from './controller'; +import Router from './router'; +import WorkspaceListView from './workspace-list-view'; +import WorkspaceHeaderView from './workspace-header-view'; +import FacetsView from './facets-view'; +import HeaderView from './HeaderView'; + +const App = new Marionette.Application(); +const init = function (el) { + this.state = new State({ canBulkChange: !!window.SS.user }); + this.list = new Issues(); + this.facets = new Facets(); + + this.layout = new Layout({ app: this, el }); + this.layout.render(); + $('#footer').addClass('search-navigator-footer'); + + this.controller = new Controller({ app: this }); + + this.issuesView = new WorkspaceListView({ + app: this, + collection: this.list + }); + this.layout.workspaceListRegion.show(this.issuesView); + this.issuesView.bindScrollEvents(); + + this.workspaceHeaderView = new WorkspaceHeaderView({ + app: this, + collection: this.list + }); + this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView); + + this.facetsView = new FacetsView({ + app: this, + collection: this.facets + }); + this.layout.facetsRegion.show(this.facetsView); + + this.headerView = new HeaderView({ + app: this + }); + this.layout.filtersRegion.show(this.headerView); + + key.setScope('list'); + App.router = new Router({ app: App }); + Backbone.history.start(); +}; + +App.on('start', function (el) { + init.call(App, el); +}); + +export default function (el) { + App.start(el); +} + diff --git a/server/sonar-web/src/main/js/apps/issues/routes.js b/server/sonar-web/src/main/js/apps/issues/routes.js new file mode 100644 index 00000000000..a05f0ec92d2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import IssuesAppContainer from './components/IssuesAppContainer'; + +export default ( + +); diff --git a/server/sonar-web/src/main/js/apps/maintenance/app.js b/server/sonar-web/src/main/js/apps/maintenance/app.js deleted file mode 100644 index 6ed1c7dbce0..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/app.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 _ from 'underscore'; -import Backbone from 'backbone'; -import Marionette from 'backbone.marionette'; -import MainView from './main-view'; - -const App = new Marionette.Application(); - -App.on('start', function () { - const options = window.sonarqube; - - const viewOptions = _.extend(options, { - model: new Backbone.Model() - }); - const mainView = new MainView(viewOptions); - mainView.render().refresh(); -}); - -App.start(); - diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.js b/server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.js new file mode 100644 index 00000000000..1419251f259 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import init from '../init'; + +export default class MaintenanceAppContainer extends React.Component { + componentDidMount () { + init(this.refs.container, false); + } + + render () { + return
        ; + } +} diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.js b/server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.js new file mode 100644 index 00000000000..4fb0c472b00 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import init from '../init'; + +export default class SetupAppContainer extends React.Component { + componentDidMount () { + init(this.refs.container, true); + } + + render () { + return
        ; + } +} diff --git a/server/sonar-web/src/main/js/apps/maintenance/init.js b/server/sonar-web/src/main/js/apps/maintenance/init.js new file mode 100644 index 00000000000..3b812525570 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/maintenance/init.js @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 _ from 'underscore'; +import Backbone from 'backbone'; +import Marionette from 'backbone.marionette'; +import MainView from './main-view'; + +const App = new Marionette.Application(); + +App.on('start', function (options) { + const viewOptions = _.extend(options, { + model: new Backbone.Model() + }); + const mainView = new MainView(viewOptions); + mainView.render().refresh(); +}); + +export default function (el, setup) { + App.start({ el, setup }); +} + diff --git a/server/sonar-web/src/main/js/apps/maintenance/routes.js b/server/sonar-web/src/main/js/apps/maintenance/routes.js new file mode 100644 index 00000000000..259894f544c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/maintenance/routes.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import MaintenanceAppContainer from './components/MaintenanceAppContainer'; +import SetupAppContainer from './components/SetupAppContainer'; + +export const maintenanceRoutes = ( + +); + +export const setupRoutes = ( + +); diff --git a/server/sonar-web/src/main/js/apps/markdown/app.js b/server/sonar-web/src/main/js/apps/markdown/app.js deleted file mode 100644 index e6b264a6885..00000000000 --- a/server/sonar-web/src/main/js/apps/markdown/app.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 Marionette from 'backbone.marionette'; -import MarkdownView from './markdown-help-view'; - -const App = new Marionette.Application(); - -App.on('start', function () { - const options = window.sonarqube; - new MarkdownView({ el: options.el }).render(); -}); - -window.sonarqube.appStarted.then(options => App.start(options)); - diff --git a/server/sonar-web/src/main/js/apps/markdown/markdown-help-view.js b/server/sonar-web/src/main/js/apps/markdown/markdown-help-view.js deleted file mode 100644 index 95235579e99..00000000000 --- a/server/sonar-web/src/main/js/apps/markdown/markdown-help-view.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 Marionette from 'backbone.marionette'; -import Template from './templates/markdown-help.hbs'; - -export default Marionette.ItemView.extend({ - template: Template -}); - diff --git a/server/sonar-web/src/main/js/apps/markdown/templates/markdown-help.hbs b/server/sonar-web/src/main/js/apps/markdown/templates/markdown-help.hbs deleted file mode 100644 index dbcabaf2227..00000000000 --- a/server/sonar-web/src/main/js/apps/markdown/templates/markdown-help.hbs +++ /dev/null @@ -1,100 +0,0 @@ -

        Markdown Syntax

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Write:To display:
        *this text is bold*this text is bold
        http://sonarqube.orghttp://sonarqube.org
        - [SonarQube™ Home Page](http://www.sonarqube.org) - - SonarQube™ Home Page -
        * first item
        - * second item -
        -
          -
        • first item
        • -
        • second item
        • -
        -
        1. first item
        - 1. second item -
        -
          -
        1. first item
        2. -
        3. second item
        4. -
        -
        - = Heading Level 1
        - == Heading Level 2
        - === Heading Level 3
        - ==== Heading Level 4
        - ===== Heading Level 5
        - ====== Heading Level 6
        -
        -

        Heading Level 1

        -

        Heading Level 2

        -

        Heading Level 3

        -

        Heading Level 4

        -
        Heading Level 5
        -
        Heading Level 6
        -
        ``Lists#newArrayList()``Lists#newArrayList()
        - ``
        - // code on multiple lines
        - public void foo() {
        -   // do some logic here
        - }
        - `` -
        -
        -  // code on multiple lines
        -  public void foo() {
        -  // do some logic here
        -  }
        -
        -
        - Standard text
        - > Blockquoted text
        - > that spans multiple lines
        -
        -

        Standard text

        -
        Blockquoted text
        - that spans multiple lines
        -
        diff --git a/server/sonar-web/src/main/js/apps/metrics/app.js b/server/sonar-web/src/main/js/apps/metrics/app.js deleted file mode 100644 index 542a5073d17..00000000000 --- a/server/sonar-web/src/main/js/apps/metrics/app.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 $ from 'jquery'; -import Marionette from 'backbone.marionette'; -import Layout from './layout'; -import Metrics from './metrics'; -import HeaderView from './header-view'; -import ListView from './list-view'; -import ListFooterView from './list-footer-view'; - -const App = new Marionette.Application(); -const init = function () { - const options = window.sonarqube; - - // Layout - this.layout = new Layout({ el: options.el }); - this.layout.render(); - - // Collection - this.metrics = new Metrics(); - - // Header View - this.headerView = new HeaderView({ - collection: this.metrics, - domains: this.domains, - types: this.types, - app: App - }); - this.layout.headerRegion.show(this.headerView); - - // List View - this.listView = new ListView({ - collection: this.metrics, - domains: this.domains, - types: this.types - }); - this.layout.listRegion.show(this.listView); - - // List Footer View - this.listFooterView = new ListFooterView({ collection: this.metrics }); - this.layout.listFooterRegion.show(this.listFooterView); - - // Go! - this.metrics.fetch(); -}; - -App.requestDomains = function () { - return $.get(window.baseUrl + '/api/metrics/domains').done(function (r) { - App.domains = r.domains; - }); -}; -App.requestTypes = function () { - return $.get(window.baseUrl + '/api/metrics/types').done(function (r) { - App.types = r.types; - }); -}; - -App.on('start', function () { - $.when(App.requestDomains(), App.requestTypes()).done(function () { - init.call(App); - }); -}); - -window.sonarqube.appStarted.then(options => App.start(options)); - diff --git a/server/sonar-web/src/main/js/apps/metrics/components/MetricsAppContainer.js b/server/sonar-web/src/main/js/apps/metrics/components/MetricsAppContainer.js new file mode 100644 index 00000000000..765ead2248a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/metrics/components/MetricsAppContainer.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import init from '../init'; + +export default class MetricsAppContainer extends React.Component { + componentDidMount () { + init(this.refs.container); + } + + render () { + return
        ; + } +} diff --git a/server/sonar-web/src/main/js/apps/metrics/init.js b/server/sonar-web/src/main/js/apps/metrics/init.js new file mode 100644 index 00000000000..06f12f34ff2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/metrics/init.js @@ -0,0 +1,82 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 $ from 'jquery'; +import Marionette from 'backbone.marionette'; +import Layout from './layout'; +import Metrics from './metrics'; +import HeaderView from './header-view'; +import ListView from './list-view'; +import ListFooterView from './list-footer-view'; + +const App = new Marionette.Application(); +const init = function (el) { + // Layout + this.layout = new Layout({ el }); + this.layout.render(); + + // Collection + this.metrics = new Metrics(); + + // Header View + this.headerView = new HeaderView({ + collection: this.metrics, + domains: this.domains, + types: this.types, + app: App + }); + this.layout.headerRegion.show(this.headerView); + + // List View + this.listView = new ListView({ + collection: this.metrics, + domains: this.domains, + types: this.types + }); + this.layout.listRegion.show(this.listView); + + // List Footer View + this.listFooterView = new ListFooterView({ collection: this.metrics }); + this.layout.listFooterRegion.show(this.listFooterView); + + // Go! + this.metrics.fetch(); +}; + +App.requestDomains = function () { + return $.get(window.baseUrl + '/api/metrics/domains').done(function (r) { + App.domains = r.domains; + }); +}; +App.requestTypes = function () { + return $.get(window.baseUrl + '/api/metrics/types').done(function (r) { + App.types = r.types; + }); +}; + +App.on('start', function (el) { + $.when(App.requestDomains(), App.requestTypes()).done(function () { + init.call(App, el); + }); +}); + +export default function (el) { + App.start(el); +} + diff --git a/server/sonar-web/src/main/js/apps/metrics/routes.js b/server/sonar-web/src/main/js/apps/metrics/routes.js new file mode 100644 index 00000000000..84955baa23e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/metrics/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import MetricsAppContainer from './components/MetricsAppContainer'; + +export default ( + +); diff --git a/server/sonar-web/src/main/js/apps/overview/app.js b/server/sonar-web/src/main/js/apps/overview/app.js deleted file mode 100644 index 5d8ad1b4a17..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/app.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { render } from 'react-dom'; - -import App from './components/App'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - const component = { ...options.component, ...window.sonarqube.overview.component }; - render(( - - ), el); -}); diff --git a/server/sonar-web/src/main/js/apps/overview/components/AppContainer.js b/server/sonar-web/src/main/js/apps/overview/components/AppContainer.js new file mode 100644 index 00000000000..85d09db946d --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/components/AppContainer.js @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import App from './App'; + +export default class AppContainer extends React.Component { + state = {}; + + componentDidMount () { + window.sonarqube.appStarted.then(options => { + this.setState({ component: options.component }); + }); + } + + render () { + if (!this.state.component) { + return null; + } + + const component = { ...this.state.component, ...window.sonarqube.overview.component }; + + return ( + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/overview/routes.js b/server/sonar-web/src/main/js/apps/overview/routes.js new file mode 100644 index 00000000000..6fac11a62ab --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/routes.js @@ -0,0 +1,28 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute, Route } from 'react-router'; +import AppContainer from './components/AppContainer'; + +export default [ + , + , + +]; diff --git a/server/sonar-web/src/main/js/apps/permission-templates/app.js b/server/sonar-web/src/main/js/apps/permission-templates/app.js deleted file mode 100644 index 036918421e7..00000000000 --- a/server/sonar-web/src/main/js/apps/permission-templates/app.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { render } from 'react-dom'; -import { Router, Route, useRouterHistory } from 'react-router'; -import { createHistory } from 'history'; -import App from './components/App'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - - const history = useRouterHistory(createHistory)({ - basename: window.baseUrl + '/permission_templates' - }); - - const EnhancedApp = props => ( - - ); - - render(( - - - - ), el); -}); diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/ActionsCell.js b/server/sonar-web/src/main/js/apps/permission-templates/components/ActionsCell.js index bd538f0a2e0..d4d5b55c456 100644 --- a/server/sonar-web/src/main/js/apps/permission-templates/components/ActionsCell.js +++ b/server/sonar-web/src/main/js/apps/permission-templates/components/ActionsCell.js @@ -152,7 +152,7 @@ export default class ActionsCell extends React.Component { {!this.props.fromDetails && (
      • - + {this.renderDropdownIcon()} Edit Permissions diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/AppContainer.js b/server/sonar-web/src/main/js/apps/permission-templates/components/AppContainer.js new file mode 100644 index 00000000000..b6f4134f066 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/permission-templates/components/AppContainer.js @@ -0,0 +1,41 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import App from './App'; + +export default class AppContainer extends React.Component { + state = {}; + + componentDidMount () { + window.sonarqube.appStarted.then(options => { + this.setState({ rootQualifiers: options.rootQualifiers }); + }); + } + + render () { + if (!this.state.rootQualifiers) { + return null; + } + + return ( + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/NameCell.js b/server/sonar-web/src/main/js/apps/permission-templates/components/NameCell.js index 8517610eb10..0e9a8b2e6be 100644 --- a/server/sonar-web/src/main/js/apps/permission-templates/components/NameCell.js +++ b/server/sonar-web/src/main/js/apps/permission-templates/components/NameCell.js @@ -33,7 +33,7 @@ export default class NameCell extends React.Component { return ( - + {t.name} diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/TemplateHeader.js b/server/sonar-web/src/main/js/apps/permission-templates/components/TemplateHeader.js index a92388d1f40..57dd6349760 100644 --- a/server/sonar-web/src/main/js/apps/permission-templates/components/TemplateHeader.js +++ b/server/sonar-web/src/main/js/apps/permission-templates/components/TemplateHeader.js @@ -36,7 +36,7 @@ export default class TemplateHeader extends React.Component { return (
        - + {translate('permission_templates.page')}
        diff --git a/server/sonar-web/src/main/js/apps/permission-templates/routes.js b/server/sonar-web/src/main/js/apps/permission-templates/routes.js new file mode 100644 index 00000000000..799d82546f9 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/permission-templates/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import AppContainer from './components/AppContainer'; + +export default ( + +); diff --git a/server/sonar-web/src/main/js/apps/permissions/global/app.js b/server/sonar-web/src/main/js/apps/permissions/global/app.js deleted file mode 100644 index db8e2981d9c..00000000000 --- a/server/sonar-web/src/main/js/apps/permissions/global/app.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { render } from 'react-dom'; -import { Provider } from 'react-redux'; -import App from './components/App'; -import configureStore from '../../../components/store/configureStore'; -import rootReducer from '../shared/store/rootReducer'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - const store = configureStore(rootReducer); - render(( - - - - ), el); -}); diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.js b/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.js index bb7b24fd24b..56343415027 100644 --- a/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.js +++ b/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.js @@ -22,23 +22,23 @@ import { connect } from 'react-redux'; import SearchForm from '../../shared/components/SearchForm'; import HoldersList from '../../shared/components/HoldersList'; import { - loadHolders, - grantToUser, - revokeFromUser, - grantToGroup, - revokeFromGroup, - updateFilter, - updateQuery, - selectPermission + loadHolders, + grantToUser, + revokeFromUser, + grantToGroup, + revokeFromGroup, + updateFilter, + updateQuery, + selectPermission } from '../store/actions'; -import { - getUsers, - getGroups, - getQuery, - getFilter, - getSelectedPermission -} from '../../shared/store/rootReducer'; import { translate } from '../../../../helpers/l10n'; +import { + getPermissionsAppUsers, + getPermissionsAppGroups, + getPermissionsAppQuery, + getPermissionsAppFilter, + getPermissionsAppSelectedPermission +} from '../../../../app/store/rootReducer'; const PERMISSIONS_ORDER = [ 'admin', @@ -102,11 +102,11 @@ class AllHoldersList extends React.Component { } const mapStateToProps = state => ({ - users: getUsers(state), - groups: getGroups(state), - query: getQuery(state), - filter: getFilter(state), - selectedPermission: getSelectedPermission(state) + users: getPermissionsAppUsers(state), + groups: getPermissionsAppGroups(state), + query: getPermissionsAppQuery(state), + filter: getPermissionsAppFilter(state), + selectedPermission: getPermissionsAppSelectedPermission(state) }); const mapDispatchToProps = dispatch => ({ diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/PageHeader.js b/server/sonar-web/src/main/js/apps/permissions/global/components/PageHeader.js index 23b750a2dd2..299de992836 100644 --- a/server/sonar-web/src/main/js/apps/permissions/global/components/PageHeader.js +++ b/server/sonar-web/src/main/js/apps/permissions/global/components/PageHeader.js @@ -21,7 +21,7 @@ import React from 'react'; import { connect } from 'react-redux'; import { translate } from '../../../../helpers/l10n'; import { loadHolders } from '../store/actions'; -import { isLoading } from '../../shared/store/rootReducer'; +import { isPermissionsAppLoading } from '../../../../app/store/rootReducer'; class PageHeader extends React.Component { static propTypes = { @@ -53,7 +53,7 @@ class PageHeader extends React.Component { } const mapStateToProps = state => ({ - loading: isLoading(state) + loading: isPermissionsAppLoading(state) }); const mapDispatchToProps = dispatch => ({ diff --git a/server/sonar-web/src/main/js/apps/permissions/global/store/actions.js b/server/sonar-web/src/main/js/apps/permissions/global/store/actions.js index 3a7d1fa158d..207a0cf7e0a 100644 --- a/server/sonar-web/src/main/js/apps/permissions/global/store/actions.js +++ b/server/sonar-web/src/main/js/apps/permissions/global/store/actions.js @@ -19,19 +19,30 @@ */ import * as api from '../../../../api/permissions'; import { parseError } from '../../../code/utils'; -import { raiseError } from '../../shared/store/actions'; import { - getQuery, - getFilter, - getSelectedPermission -} from '../../shared/store/rootReducer'; + raiseError, + REQUEST_HOLDERS, + RECEIVE_HOLDERS_SUCCESS, + UPDATE_QUERY, + UPDATE_FILTER, + SELECT_PERMISSION, + GRANT_PERMISSION_TO_USER, + REVOKE_PERMISSION_TO_USER, + GRANT_PERMISSION_TO_GROUP, + REVOKE_PERMISSION_FROM_GROUP +} from '../../shared/store/actions'; +import { + getPermissionsAppQuery, + getPermissionsAppFilter, + getPermissionsAppSelectedPermission +} from '../../../../app/store/rootReducer'; export const loadHolders = () => (dispatch, getState) => { - const query = getQuery(getState()); - const filter = getFilter(getState()); - const selectedPermission = getSelectedPermission(getState()); + const query = getPermissionsAppQuery(getState()); + const filter = getPermissionsAppFilter(getState()); + const selectedPermission = getPermissionsAppSelectedPermission(getState()); - dispatch({ type: 'REQUEST_HOLDERS', query }); + dispatch({ type: REQUEST_HOLDERS, query }); const requests = []; @@ -49,7 +60,7 @@ export const loadHolders = () => (dispatch, getState) => { return Promise.all(requests).then(responses => ( dispatch({ - type: 'RECEIVE_HOLDERS_SUCCESS', + type: RECEIVE_HOLDERS_SUCCESS, users: responses[0], groups: responses[1], query @@ -60,30 +71,30 @@ export const loadHolders = () => (dispatch, getState) => { }; export const updateQuery = (query = '') => dispatch => { - dispatch({ type: 'UPDATE_QUERY', query }); + dispatch({ type: UPDATE_QUERY, query }); if (query.length === 0 || query.length > 2) { dispatch(loadHolders()); } }; export const updateFilter = filter => dispatch => { - dispatch({ type: 'UPDATE_FILTER', filter }); + dispatch({ type: UPDATE_FILTER, filter }); dispatch(loadHolders()); }; export const selectPermission = permission => (dispatch, getState) => { - const selectedPermission = getSelectedPermission(getState()); + const selectedPermission = getPermissionsAppSelectedPermission(getState()); if (selectedPermission !== permission) { - dispatch({ type: 'SELECT_PERMISSION', permission }); + dispatch({ type: SELECT_PERMISSION, permission }); } else { - dispatch({ type: 'SELECT_PERMISSION', permission: null }); + dispatch({ type: SELECT_PERMISSION, permission: null }); } dispatch(loadHolders()); }; export const grantToUser = (login, permission) => dispatch => { api.grantPermissionToUser(null, login, permission).then(() => { - dispatch({ type: 'GRANT_PERMISSION_TO_USER', login, permission }); + dispatch({ type: GRANT_PERMISSION_TO_USER, login, permission }); }).catch(e => { return parseError(e).then(message => dispatch(raiseError(message))); }); @@ -91,7 +102,7 @@ export const grantToUser = (login, permission) => dispatch => { export const revokeFromUser = (login, permission) => dispatch => { api.revokePermissionFromUser(null, login, permission).then(() => { - dispatch({ type: 'REVOKE_PERMISSION_TO_USER', login, permission }); + dispatch({ type: REVOKE_PERMISSION_TO_USER, login, permission }); }).catch(e => { return parseError(e).then(message => dispatch(raiseError(message))); }); @@ -100,7 +111,7 @@ export const revokeFromUser = (login, permission) => dispatch => { export const grantToGroup = (groupName, permission) => dispatch => { api.grantPermissionToGroup(null, groupName, permission).then(() => { dispatch({ - type: 'GRANT_PERMISSION_TO_GROUP', + type: GRANT_PERMISSION_TO_GROUP, groupName, permission }); @@ -112,7 +123,7 @@ export const grantToGroup = (groupName, permission) => dispatch => { export const revokeFromGroup = (groupName, permission) => dispatch => { api.revokePermissionFromGroup(null, groupName, permission).then(() => { dispatch({ - type: 'REVOKE_PERMISSION_FROM_GROUP', + type: REVOKE_PERMISSION_FROM_GROUP, groupName, permission }); diff --git a/server/sonar-web/src/main/js/apps/permissions/project/app.js b/server/sonar-web/src/main/js/apps/permissions/project/app.js deleted file mode 100644 index 1646df7ef24..00000000000 --- a/server/sonar-web/src/main/js/apps/permissions/project/app.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { render } from 'react-dom'; -import { Provider } from 'react-redux'; -import App from './components/App'; -import configureStore from '../../../components/store/configureStore'; -import rootReducer from '../shared/store/rootReducer'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - const store = configureStore(rootReducer); - render(( - - - - ), el); -}); diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.js b/server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.js index 6dcbe728084..63b041b2fcf 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.js +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.js @@ -22,24 +22,24 @@ import { connect } from 'react-redux'; import SearchForm from '../../shared/components/SearchForm'; import HoldersList from '../../shared/components/HoldersList'; import { - loadHolders, - grantToUser, - revokeFromUser, - grantToGroup, - revokeFromGroup, - updateQuery, - updateFilter, - selectPermission + loadHolders, + grantToUser, + revokeFromUser, + grantToGroup, + revokeFromGroup, + updateQuery, + updateFilter, + selectPermission } from '../store/actions'; -import { - getUsers, - getGroups, - getQuery, - getFilter, - getSelectedPermission -} from '../../shared/store/rootReducer'; import { translate } from '../../../../helpers/l10n'; import { PERMISSIONS_ORDER_BY_QUALIFIER } from '../constants'; +import { + getPermissionsAppUsers, + getPermissionsAppGroups, + getPermissionsAppQuery, + getPermissionsAppFilter, + getPermissionsAppSelectedPermission +} from '../../../../app/store/rootReducer'; class AllHoldersList extends React.Component { static propTypes = { @@ -128,11 +128,11 @@ class AllHoldersList extends React.Component { } const mapStateToProps = state => ({ - users: getUsers(state), - groups: getGroups(state), - query: getQuery(state), - filter: getFilter(state), - selectedPermission: getSelectedPermission(state) + users: getPermissionsAppUsers(state), + groups: getPermissionsAppGroups(state), + query: getPermissionsAppQuery(state), + filter: getPermissionsAppFilter(state), + selectedPermission: getPermissionsAppSelectedPermission(state) }); const mapDispatchToProps = dispatch => ({ 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 d8bc447fa08..ba2b4e44e2e 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 @@ -27,15 +27,19 @@ import '../../styles.css'; export default class App extends React.Component { static propTypes = { - project: React.PropTypes.object.isRequired + component: React.PropTypes.object }; render () { + if (!this.props.component) { + return null; + } + return (
        - + - +
        ); } diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.js b/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.js index db60031625d..14fcf947ee9 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.js +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.js @@ -22,7 +22,7 @@ import { connect } from 'react-redux'; import { translate } from '../../../../helpers/l10n'; import ApplyTemplateView from '../views/ApplyTemplateView'; import { loadHolders } from '../store/actions'; -import { isLoading } from '../../shared/store/rootReducer'; +import { isPermissionsAppLoading } from '../../../../app/store/rootReducer'; class PageHeader extends React.Component { static propTypes = { @@ -76,7 +76,7 @@ class PageHeader extends React.Component { } const mapStateToProps = state => ({ - loading: isLoading(state) + loading: isPermissionsAppLoading(state) }); const mapDispatchToProps = dispatch => ({ diff --git a/server/sonar-web/src/main/js/apps/permissions/project/store/actions.js b/server/sonar-web/src/main/js/apps/permissions/project/store/actions.js index 5011dc075ad..b705876a6a2 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/store/actions.js +++ b/server/sonar-web/src/main/js/apps/permissions/project/store/actions.js @@ -19,19 +19,30 @@ */ import * as api from '../../../../api/permissions'; import { parseError } from '../../../code/utils'; -import { raiseError } from '../../shared/store/actions'; import { - getQuery, - getFilter, - getSelectedPermission -} from '../../shared/store/rootReducer'; + raiseError, + REQUEST_HOLDERS, + RECEIVE_HOLDERS_SUCCESS, + UPDATE_QUERY, + UPDATE_FILTER, + SELECT_PERMISSION, + GRANT_PERMISSION_TO_USER, + REVOKE_PERMISSION_TO_USER, + GRANT_PERMISSION_TO_GROUP, + REVOKE_PERMISSION_FROM_GROUP +} from '../../shared/store/actions'; +import { + getPermissionsAppQuery, + getPermissionsAppFilter, + getPermissionsAppSelectedPermission +} from '../../../../app/store/rootReducer'; export const loadHolders = projectKey => (dispatch, getState) => { - const query = getQuery(getState()); - const filter = getFilter(getState()); - const selectedPermission = getSelectedPermission(getState()); + const query = getPermissionsAppQuery(getState()); + const filter = getPermissionsAppFilter(getState()); + const selectedPermission = getPermissionsAppSelectedPermission(getState()); - dispatch({ type: 'REQUEST_HOLDERS', query }); + dispatch({ type: REQUEST_HOLDERS, query }); const requests = []; @@ -51,7 +62,7 @@ export const loadHolders = projectKey => (dispatch, getState) => { return Promise.all(requests).then(responses => ( dispatch({ - type: 'RECEIVE_HOLDERS_SUCCESS', + type: RECEIVE_HOLDERS_SUCCESS, users: responses[0], groups: responses[1], query @@ -62,30 +73,30 @@ export const loadHolders = projectKey => (dispatch, getState) => { }; export const updateQuery = (projectKey, query = '') => dispatch => { - dispatch({ type: 'UPDATE_QUERY', query }); + dispatch({ type: UPDATE_QUERY, query }); if (query.length === 0 || query.length > 2) { dispatch(loadHolders(projectKey)); } }; export const updateFilter = (projectKey, filter) => dispatch => { - dispatch({ type: 'UPDATE_FILTER', filter }); + dispatch({ type: UPDATE_FILTER, filter }); dispatch(loadHolders(projectKey)); }; export const selectPermission = (projectKey, permission) => (dispatch, getState) => { - const selectedPermission = getSelectedPermission(getState()); + const selectedPermission = getPermissionsAppSelectedPermission(getState()); if (selectedPermission !== permission) { - dispatch({ type: 'SELECT_PERMISSION', permission }); + dispatch({ type: SELECT_PERMISSION, permission }); } else { - dispatch({ type: 'SELECT_PERMISSION', permission: null }); + dispatch({ type: SELECT_PERMISSION, permission: null }); } dispatch(loadHolders(projectKey)); }; export const grantToUser = (projectKey, login, permission) => dispatch => { api.grantPermissionToUser(projectKey, login, permission).then(() => { - dispatch({ type: 'GRANT_PERMISSION_TO_USER', login, permission }); + dispatch({ type: GRANT_PERMISSION_TO_USER, login, permission }); }).catch(e => { return parseError(e).then(message => dispatch(raiseError(message))); }); @@ -93,7 +104,7 @@ export const grantToUser = (projectKey, login, permission) => dispatch => { export const revokeFromUser = (projectKey, login, permission) => dispatch => { api.revokePermissionFromUser(projectKey, login, permission).then(() => { - dispatch({ type: 'REVOKE_PERMISSION_TO_USER', login, permission }); + dispatch({ type: REVOKE_PERMISSION_TO_USER, login, permission }); }).catch(e => { return parseError(e).then(message => dispatch(raiseError(message))); }); @@ -102,7 +113,7 @@ export const revokeFromUser = (projectKey, login, permission) => dispatch => { export const grantToGroup = (projectKey, groupName, permission) => dispatch => { api.grantPermissionToGroup(projectKey, groupName, permission).then(() => { dispatch({ - type: 'GRANT_PERMISSION_TO_GROUP', + type: GRANT_PERMISSION_TO_GROUP, groupName, permission }); @@ -114,7 +125,7 @@ export const grantToGroup = (projectKey, groupName, permission) => dispatch => { export const revokeFromGroup = (projectKey, groupName, permission) => dispatch => { api.revokePermissionFromGroup(projectKey, groupName, permission).then(() => { dispatch({ - type: 'REVOKE_PERMISSION_FROM_GROUP', + type: REVOKE_PERMISSION_FROM_GROUP, groupName, permission }); diff --git a/server/sonar-web/src/main/js/apps/permissions/routes.js b/server/sonar-web/src/main/js/apps/permissions/routes.js new file mode 100644 index 00000000000..a273a2914b6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/permissions/routes.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import GlobalPermissionsApp from './global/components/App'; +import ProjectPermissionsApp from './project/components/App'; + +export const globalPermissionsRoutes = ( + +); + +export const projectPermissionsRoutes = ( + +); diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.js b/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.js index 3449153a921..289a6c196a0 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.js @@ -19,7 +19,7 @@ */ import React from 'react'; import { connect } from 'react-redux'; -import { getError } from '../store/rootReducer'; +import { getPermissionsAppError } from '../../../../app/store/rootReducer'; class PageError extends React.Component { static propTypes = { @@ -42,7 +42,7 @@ class PageError extends React.Component { } const mapStateToProps = state => ({ - message: getError(state) + message: getPermissionsAppError(state) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/actions.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/actions.js index be7cee4a4b7..ceed4f2f9ec 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/store/actions.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/actions.js @@ -17,7 +17,18 @@ * 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_HOLDERS_SUCCESS = 'permissions/RECEIVE_HOLDERS_SUCCESS'; +export const GRANT_PERMISSION_TO_GROUP = 'permissions/GRANT_PERMISSION_TO_GROUP'; +export const REVOKE_PERMISSION_FROM_GROUP = 'permissions/REVOKE_PERMISSION_FROM_GROUP'; +export const GRANT_PERMISSION_TO_USER = 'permissions/GRANT_PERMISSION_TO_USER'; +export const REVOKE_PERMISSION_TO_USER = 'permissions/REVOKE_PERMISSION_TO_USER'; +export const UPDATE_FILTER = 'permissions/UPDATE_FILTER'; +export const UPDATE_QUERY = 'permissions/UPDATE_QUERY'; +export const SELECT_PERMISSION = 'permissions/SELECT_PERMISSION'; +export const REQUEST_HOLDERS = 'permissions/REQUEST_HOLDERS'; +export const ERROR = 'permissions/ERROR'; + export const raiseError = message => ({ - type: 'ERROR', + type: ERROR, message }); diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/error.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/error.js index 6fe0ec764c3..b56a9ee6cbf 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/store/error.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/error.js @@ -17,15 +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 { + RECEIVE_HOLDERS_SUCCESS, + GRANT_PERMISSION_TO_USER, + REVOKE_PERMISSION_TO_USER, + GRANT_PERMISSION_TO_GROUP, + REVOKE_PERMISSION_FROM_GROUP, + ERROR +} from './actions'; + const error = (state = null, action = {}) => { switch (action.type) { - case 'RECEIVE_HOLDERS_SUCCESS': - case 'GRANT_PERMISSION_TO_USER': - case 'REVOKE_PERMISSION_TO_USER': - case 'GRANT_PERMISSION_TO_GROUP': - case 'REVOKE_PERMISSION_FROM_GROUP': + case RECEIVE_HOLDERS_SUCCESS: + case GRANT_PERMISSION_TO_USER: + case REVOKE_PERMISSION_TO_USER: + case GRANT_PERMISSION_TO_GROUP: + case REVOKE_PERMISSION_FROM_GROUP: return null; - case 'ERROR': + case ERROR: return action.message; default: return state; diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/filter.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/filter.js index 6934582b425..65fa36db24d 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/store/filter.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/filter.js @@ -17,9 +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 { UPDATE_FILTER } from './actions'; + const filter = (state = 'all', action = {}) => { switch (action.type) { - case 'UPDATE_FILTER': + case UPDATE_FILTER: return action.filter; default: return state; diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/byName.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/byName.js index c1475aa6763..a015820d0df 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/byName.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/byName.js @@ -18,16 +18,17 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import keyBy from 'lodash/keyBy'; +import { RECEIVE_HOLDERS_SUCCESS, GRANT_PERMISSION_TO_GROUP, REVOKE_PERMISSION_FROM_GROUP } from '../actions'; const byName = (state = {}, action = {}) => { - if (action.type === 'RECEIVE_HOLDERS_SUCCESS') { + if (action.type === RECEIVE_HOLDERS_SUCCESS) { const newGroups = keyBy(action.groups, 'name'); return { ...state, ...newGroups }; - } else if (action.type === 'GRANT_PERMISSION_TO_GROUP') { + } else if (action.type === GRANT_PERMISSION_TO_GROUP) { const newGroup = { ...state[action.groupName] }; newGroup.permissions = [...newGroup.permissions, action.permission]; return { ...state, [action.groupName]: newGroup }; - } else if (action.type === 'REVOKE_PERMISSION_FROM_GROUP') { + } else if (action.type === REVOKE_PERMISSION_FROM_GROUP) { const newGroup = { ...state[action.groupName] }; newGroup.permissions = newGroup.permissions .filter(p => p !== action.permission); diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/names.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/names.js index 8451a26999e..4dbf7b34c8d 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/names.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/names.js @@ -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 { RECEIVE_HOLDERS_SUCCESS } from '../actions'; + const names = (state = [], action = {}) => { - if (action.type === 'RECEIVE_HOLDERS_SUCCESS') { + if (action.type === RECEIVE_HOLDERS_SUCCESS) { return action.groups.map(group => group.name); } else { return state; diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/loading.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/loading.js index b7ff6d172bc..87d7ee4d900 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/store/loading.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/loading.js @@ -17,11 +17,13 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { REQUEST_HOLDERS, RECEIVE_HOLDERS_SUCCESS } from './actions'; + const loading = (state = false, action = {}) => { switch (action.type) { - case 'REQUEST_HOLDERS': + case REQUEST_HOLDERS: return true; - case 'RECEIVE_HOLDERS_SUCCESS': + case RECEIVE_HOLDERS_SUCCESS: return false; default: return state; diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/query.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/query.js index 49a755a3fee..b8dbc36a794 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/store/query.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/query.js @@ -17,10 +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 { UPDATE_QUERY, REQUEST_HOLDERS } from './actions'; + const query = (state = '', action = {}) => { switch (action.type) { - case 'UPDATE_QUERY': - case 'REQUEST_HOLDERS': + case UPDATE_QUERY: + case REQUEST_HOLDERS: return action.query; default: return state; diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/selectedPermission.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/selectedPermission.js index c4e951745d7..b44531e3c12 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/store/selectedPermission.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/selectedPermission.js @@ -17,9 +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 { SELECT_PERMISSION } from './actions'; + const selectedPermission = (state = null, action = {}) => { switch (action.type) { - case 'SELECT_PERMISSION': + case SELECT_PERMISSION: return action.permission; default: return state; diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/users/byLogin.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/users/byLogin.js index a571966cd92..fd3d21db256 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/store/users/byLogin.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/users/byLogin.js @@ -18,16 +18,17 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import keyBy from 'lodash/keyBy'; +import { RECEIVE_HOLDERS_SUCCESS, GRANT_PERMISSION_TO_USER, REVOKE_PERMISSION_TO_USER } from '../actions'; const byLogin = (state = {}, action = {}) => { - if (action.type === 'RECEIVE_HOLDERS_SUCCESS') { + if (action.type === RECEIVE_HOLDERS_SUCCESS) { const newUsers = keyBy(action.users, 'login'); return { ...state, ...newUsers }; - } else if (action.type === 'GRANT_PERMISSION_TO_USER') { + } else if (action.type === GRANT_PERMISSION_TO_USER) { const newUser = { ...state[action.login] }; newUser.permissions = [...newUser.permissions, action.permission]; return { ...state, [action.login]: newUser }; - } else if (action.type === 'REVOKE_PERMISSION_TO_USER') { + } else if (action.type === REVOKE_PERMISSION_TO_USER) { const newUser = { ...state[action.login] }; newUser.permissions = newUser.permissions .filter(p => p !== action.permission); diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/users/logins.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/users/logins.js index b0bc1e31ca0..ad32bdc8573 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/store/users/logins.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/users/logins.js @@ -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 { RECEIVE_HOLDERS_SUCCESS } from '../actions'; + const logins = (state = [], action = {}) => { - if (action.type === 'RECEIVE_HOLDERS_SUCCESS') { + if (action.type === RECEIVE_HOLDERS_SUCCESS) { return action.users.map(user => user.login); } else { return state; diff --git a/server/sonar-web/src/main/js/apps/project-admin/app.js b/server/sonar-web/src/main/js/apps/project-admin/app.js deleted file mode 100644 index 903ed046cb9..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/app.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { render } from 'react-dom'; -import { Provider } from 'react-redux'; -import { Router, Route, useRouterHistory } from 'react-router'; -import { createHistory } from 'history'; -import Deletion from './deletion/Deletion'; -import QualityProfiles from './quality-profiles/QualityProfiles'; -import QualityGate from './quality-gate/QualityGate'; -import Links from './links/Links'; -import Key from './key/Key'; -import rootReducer from './store/rootReducer'; -import configureStore from '../../components/store/configureStore'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - - const history = useRouterHistory(createHistory)({ - basename: window.baseUrl + '/project' - }); - - const store = configureStore(rootReducer); - - const withComponent = ComposedComponent => props => - ; - - render(( - - - - - - - - - - ), el); -}); diff --git a/server/sonar-web/src/main/js/apps/project-admin/components/GlobalMessagesContainer.js b/server/sonar-web/src/main/js/apps/project-admin/components/GlobalMessagesContainer.js index f64ef91664b..130192047b7 100644 --- a/server/sonar-web/src/main/js/apps/project-admin/components/GlobalMessagesContainer.js +++ b/server/sonar-web/src/main/js/apps/project-admin/components/GlobalMessagesContainer.js @@ -19,10 +19,10 @@ */ import { connect } from 'react-redux'; import GlobalMessages from '../../../components/controls/GlobalMessages'; -import { getGlobalMessages } from '../store/rootReducer'; +import { getProjectAdminGlobalMessages } from '../../../app/store/rootReducer'; const mapStateToProps = state => ({ - messages: getGlobalMessages(state) + messages: getProjectAdminGlobalMessages(state) }); export default connect(mapStateToProps)(GlobalMessages); diff --git a/server/sonar-web/src/main/js/apps/project-admin/deletion/Deletion.js b/server/sonar-web/src/main/js/apps/project-admin/deletion/Deletion.js index 67563891ade..52e4fbc1774 100644 --- a/server/sonar-web/src/main/js/apps/project-admin/deletion/Deletion.js +++ b/server/sonar-web/src/main/js/apps/project-admin/deletion/Deletion.js @@ -23,10 +23,14 @@ import Form from './Form'; export default class Deletion extends React.Component { static propTypes = { - component: React.PropTypes.object.isRequired + component: React.PropTypes.object }; render () { + if (!this.props.component) { + return null; + } + return (
        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 315dc4b17f2..4bc8050a464 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 { closeAllGlobalMessages } from '../../../components/store/globalMessages'; import { reloadUpdateKeyPage } from './utils'; -import RecentHistory from '../../../main/nav/component/RecentHistory'; +import RecentHistory from '../../../app/components/nav/component/RecentHistory'; class BulkUpdate extends React.Component { static propTypes = { 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 019cde640df..f4bff8b4a59 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 @@ -25,7 +25,6 @@ import UpdateForm from './UpdateForm'; import BulkUpdate from './BulkUpdate'; import FineGrainedUpdate from './FineGrainedUpdate'; import GlobalMessagesContainer from '../components/GlobalMessagesContainer'; -import { getProjectModules } from '../store/rootReducer'; import { fetchProjectModules, changeKey } from '../store/actions'; import { translate } from '../../../helpers/l10n'; import { @@ -35,7 +34,8 @@ import { } from '../../../components/store/globalMessages'; import { parseError } from '../../code/utils'; import { reloadUpdateKeyPage } from './utils'; -import RecentHistory from '../../../main/nav/component/RecentHistory'; +import RecentHistory from '../../../app/components/nav/component/RecentHistory'; +import { getProjectAdminProjectModules } from '../../../app/store/rootReducer'; class Key extends React.Component { static propTypes = { @@ -152,7 +152,7 @@ class Key extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - modules: getProjectModules(state, ownProps.component.key) + modules: getProjectAdminProjectModules(state, ownProps.component.key) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/project-admin/links/Links.js b/server/sonar-web/src/main/js/apps/project-admin/links/Links.js index 88602532ea9..4494c52b5c9 100644 --- a/server/sonar-web/src/main/js/apps/project-admin/links/Links.js +++ b/server/sonar-web/src/main/js/apps/project-admin/links/Links.js @@ -23,12 +23,12 @@ import { connect } from 'react-redux'; import Header from './Header'; import Table from './Table'; import DeletionModal from './views/DeletionModal'; -import { getProjectLinks } from '../store/rootReducer'; import { fetchProjectLinks, deleteProjectLink, createProjectLink } from '../store/actions'; +import { getProjectAdminProjectLinks } from '../../../app/store/rootReducer'; class Links extends React.Component { static propTypes = { @@ -73,7 +73,7 @@ class Links extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - links: getProjectLinks(state, ownProps.component.key) + links: getProjectAdminProjectLinks(state, ownProps.component.key) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/project-admin/quality-gate/QualityGate.js b/server/sonar-web/src/main/js/apps/project-admin/quality-gate/QualityGate.js index e80c5b72284..0921f1f2060 100644 --- a/server/sonar-web/src/main/js/apps/project-admin/quality-gate/QualityGate.js +++ b/server/sonar-web/src/main/js/apps/project-admin/quality-gate/QualityGate.js @@ -23,8 +23,8 @@ import shallowCompare from 'react-addons-shallow-compare'; import Header from './Header'; import Form from './Form'; import GlobalMessagesContainer from '../components/GlobalMessagesContainer'; -import { getAllGates, getProjectGate } from '../store/rootReducer'; import { fetchProjectGate, setProjectGate } from '../store/actions'; +import { getProjectAdminAllGates, getProjectAdminProjectGate } from '../../../app/store/rootReducer'; class QualityGate extends React.Component { static propTypes = { @@ -60,8 +60,8 @@ class QualityGate extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - allGates: getAllGates(state), - gate: getProjectGate(state, ownProps.component.key) + allGates: getProjectAdminAllGates(state), + gate: getProjectAdminProjectGate(state, ownProps.component.key) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/project-admin/quality-profiles/QualityProfiles.js b/server/sonar-web/src/main/js/apps/project-admin/quality-profiles/QualityProfiles.js index de20aa1ad8d..9bfdab5c533 100644 --- a/server/sonar-web/src/main/js/apps/project-admin/quality-profiles/QualityProfiles.js +++ b/server/sonar-web/src/main/js/apps/project-admin/quality-profiles/QualityProfiles.js @@ -24,7 +24,7 @@ import Header from './Header'; import Table from './Table'; import GlobalMessagesContainer from '../components/GlobalMessagesContainer'; import { fetchProjectProfiles, setProjectProfile } from '../store/actions'; -import { getProjectProfiles, getAllProfiles } from '../store/rootReducer'; +import { getProjectAdminAllProfiles, getProjectAdminProjectProfiles } from '../../../app/store/rootReducer'; class QualityProfiles extends React.Component { static propTypes = { @@ -68,8 +68,8 @@ class QualityProfiles extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - allProfiles: getAllProfiles(state), - profiles: getProjectProfiles(state, ownProps.component.key) + allProfiles: getProjectAdminAllProfiles(state), + profiles: getProjectAdminProjectProfiles(state, ownProps.component.key) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/project-admin/routes.js b/server/sonar-web/src/main/js/apps/project-admin/routes.js new file mode 100644 index 00000000000..fda733c0002 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/project-admin/routes.js @@ -0,0 +1,34 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { Route } from 'react-router'; +import Deletion from './deletion/Deletion'; +import QualityProfiles from './quality-profiles/QualityProfiles'; +import QualityGate from './quality-gate/QualityGate'; +import Links from './links/Links'; +import Key from './key/Key'; + +export default [ + , + , + , + , + +]; diff --git a/server/sonar-web/src/main/js/apps/project-admin/store/actions.js b/server/sonar-web/src/main/js/apps/project-admin/store/actions.js index 18eb9917862..b5c3c1a5f21 100644 --- a/server/sonar-web/src/main/js/apps/project-admin/store/actions.js +++ b/server/sonar-web/src/main/js/apps/project-admin/store/actions.js @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { getQualityProfiles, associateProject, dissociateProject } from '../../../api/quality-profiles'; -import { getProfileByKey } from './rootReducer'; import { fetchQualityGates, getGateForProject, @@ -29,14 +28,15 @@ import { getProjectLinks, createLink } from '../../../api/projectLinks'; import { getTree, changeKey as changeKeyApi } from '../../../api/components'; import { addGlobalSuccessMessage } from '../../../components/store/globalMessages'; import { translate, translateWithParameters } from '../../../helpers/l10n'; +import { getProjectAdminProfileByKey } from '../../../app/store/rootReducer'; -export const RECEIVE_PROFILES = 'RECEIVE_PROFILES'; +export const RECEIVE_PROFILES = 'projectAdmin/RECEIVE_PROFILES'; export const receiveProfiles = profiles => ({ type: RECEIVE_PROFILES, profiles }); -export const RECEIVE_PROJECT_PROFILES = 'RECEIVE_PROJECT_PROFILES'; +export const RECEIVE_PROJECT_PROFILES = 'projectAdmin/RECEIVE_PROJECT_PROFILES'; export const receiveProjectProfiles = (projectKey, profiles) => ({ type: RECEIVE_PROJECT_PROFILES, projectKey, @@ -54,7 +54,7 @@ export const fetchProjectProfiles = projectKey => dispatch => { }); }; -export const SET_PROJECT_PROFILE = 'SET_PROJECT_PROFILE'; +export const SET_PROJECT_PROFILE = 'projectAdmin/SET_PROJECT_PROFILE'; const setProjectProfileAction = (projectKey, oldProfileKey, newProfileKey) => ({ type: SET_PROJECT_PROFILE, projectKey, @@ -65,7 +65,7 @@ const setProjectProfileAction = (projectKey, oldProfileKey, newProfileKey) => ({ export const setProjectProfile = (projectKey, oldKey, newKey) => (dispatch, getState) => { const state = getState(); - const newProfile = getProfileByKey(state, newKey); + const newProfile = getProjectAdminProfileByKey(state, newKey); const request = newProfile.isDefault ? dissociateProject(oldKey, projectKey) : associateProject(newKey, projectKey); @@ -79,13 +79,13 @@ export const setProjectProfile = (projectKey, oldKey, newKey) => }); }; -export const RECEIVE_GATES = 'RECEIVE_GATES'; +export const RECEIVE_GATES = 'projectAdmin/RECEIVE_GATES'; export const receiveGates = gates => ({ type: RECEIVE_GATES, gates }); -export const RECEIVE_PROJECT_GATE = 'RECEIVE_PROJECT_GATE'; +export const RECEIVE_PROJECT_GATE = 'projectAdmin/RECEIVE_PROJECT_GATE'; export const receiveProjectGate = (projectKey, gate) => ({ type: RECEIVE_PROJECT_GATE, projectKey, @@ -103,7 +103,7 @@ export const fetchProjectGate = projectKey => dispatch => { }); }; -export const SET_PROJECT_GATE = 'SET_PROJECT_GATE'; +export const SET_PROJECT_GATE = 'projectAdmin/SET_PROJECT_GATE'; const setProjectGateAction = (projectKey, gateId) => ({ type: SET_PROJECT_GATE, projectKey, @@ -122,7 +122,7 @@ export const setProjectGate = (projectKey, oldId, newId) => dispatch => { }); }; -export const RECEIVE_PROJECT_LINKS = 'RECEIVE_PROJECT_LINKS'; +export const RECEIVE_PROJECT_LINKS = 'projectAdmin/RECEIVE_PROJECT_LINKS'; export const receiveProjectLinks = (projectKey, links) => ({ type: RECEIVE_PROJECT_LINKS, projectKey, @@ -135,7 +135,7 @@ export const fetchProjectLinks = projectKey => dispatch => { }); }; -export const ADD_PROJECT_LINK = 'ADD_PROJECT_LINK'; +export const ADD_PROJECT_LINK = 'projectAdmin/ADD_PROJECT_LINK'; const addProjectLink = (projectKey, link) => ({ type: ADD_PROJECT_LINK, projectKey, @@ -148,14 +148,14 @@ export const createProjectLink = (projectKey, name, url) => dispatch => { }); }; -export const DELETE_PROJECT_LINK = 'DELETE_PROJECT_LINK'; +export const DELETE_PROJECT_LINK = 'projectAdmin/DELETE_PROJECT_LINK'; export const deleteProjectLink = (projectKey, linkId) => ({ type: DELETE_PROJECT_LINK, projectKey, linkId }); -export const RECEIVE_PROJECT_MODULES = 'RECEIVE_PROJECT_MODULES'; +export const RECEIVE_PROJECT_MODULES = 'projectAdmin/RECEIVE_PROJECT_MODULES'; const receiveProjectModules = (projectKey, modules) => ({ type: RECEIVE_PROJECT_MODULES, projectKey, @@ -169,7 +169,7 @@ export const fetchProjectModules = projectKey => dispatch => { }); }; -export const CHANGE_KEY = 'CHANGE_KEY'; +export const CHANGE_KEY = 'projectAdmin/CHANGE_KEY'; const changeKeyAction = (key, newKey) => ({ type: CHANGE_KEY, key, diff --git a/server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js b/server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js new file mode 100644 index 00000000000..e87d63f8ec6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js @@ -0,0 +1,55 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { connect } from 'react-redux'; +import React from 'react'; +import Main from './main'; +import { getCurrentUser } from '../../app/store/rootReducer'; + +class AppContainer extends React.Component { + state = {}; + + componentDidMount () { + window.sonarqube.appStarted.then(options => { + this.setState({ rootQualifiers: options.rootQualifiers }); + }); + } + + render () { + if (!this.props.user || !this.state.rootQualifiers) { + return null; + } + + const hasProvisionPermission = this.props.user.permissions.global.indexOf('provisioning') !== -1; + + return ( +
        + ); + } +} + +const mapStateToProps = state => ({ + user: getCurrentUser(state) +}); + +export default connect( + mapStateToProps +)(AppContainer); diff --git a/server/sonar-web/src/main/js/apps/projects-admin/app.js b/server/sonar-web/src/main/js/apps/projects-admin/app.js deleted file mode 100644 index 7c68d2c4b6e..00000000000 --- a/server/sonar-web/src/main/js/apps/projects-admin/app.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import ReactDOM from 'react-dom'; -import Main from './main'; -import { getCurrentUser } from '../../api/users'; - -window.sonarqube.appStarted.then(options => { - getCurrentUser().then(user => { - const el = document.querySelector(options.el); - const hasProvisionPermission = user.permissions.global.indexOf('provisioning') !== -1; - const topLevelQualifiers = options.rootQualifiers; - ReactDOM.render(
        , el); - }); -}); diff --git a/server/sonar-web/src/main/js/apps/projects-admin/routes.js b/server/sonar-web/src/main/js/apps/projects-admin/routes.js new file mode 100644 index 00000000000..5b25254fb7f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import AppContainer from './AppContainer'; + +export default( + +); diff --git a/server/sonar-web/src/main/js/apps/projects/routes.js b/server/sonar-web/src/main/js/apps/projects/routes.js index 114e82ca197..017baac85be 100644 --- a/server/sonar-web/src/main/js/apps/projects/routes.js +++ b/server/sonar-web/src/main/js/apps/projects/routes.js @@ -24,7 +24,7 @@ import AllProjectsContainer from './components/AllProjectsContainer'; import FavoriteProjectsContainer from './components/FavoriteProjectsContainer'; export default ( - + diff --git a/server/sonar-web/src/main/js/apps/quality-gates/routes.js b/server/sonar-web/src/main/js/apps/quality-gates/routes.js index 8f471c3930b..1a05f4e4657 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/routes.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/routes.js @@ -24,7 +24,7 @@ import Intro from './components/Intro'; import DetailsContainer from './containers/DetailsContainer'; export default ( - + diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/routes.js b/server/sonar-web/src/main/js/apps/quality-profiles/routes.js index b5729b5643b..3530edc7a91 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/routes.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/routes.js @@ -27,7 +27,7 @@ import ChangelogContainer from './changelog/ChangelogContainer'; import ComparisonContainer from './compare/ComparisonContainer'; export default ( - + diff --git a/server/sonar-web/src/main/js/apps/settings/app.js b/server/sonar-web/src/main/js/apps/settings/app.js deleted file mode 100644 index 15040500397..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/app.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { render } from 'react-dom'; -import { Provider } from 'react-redux'; -import { Router, Route, Redirect, useRouterHistory } from 'react-router'; -import { createHistory } from 'history'; -import App from './components/App'; -import LicensesApp from './licenses/LicensesApp'; -import EncryptionAppContainer from './encryption/EncryptionAppContainer'; -import ServerIdAppContainer from './serverId/ServerIdAppContainer'; -import rootReducer from './store/rootReducer'; -import configureStore from '../../components/store/configureStore'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - - const controller = options.component ? '/project/settings' : '/settings'; - const history = useRouterHistory(createHistory)({ - basename: window.baseUrl + controller - }); - - const store = configureStore(rootReducer); - - const withComponent = ComposedComponent => props => - ; - - render(( - - - - - - - - - - ), el); -}); diff --git a/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js b/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js index 285f9e769e7..96fccd0abfe 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js +++ b/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js @@ -21,7 +21,7 @@ import React from 'react'; import { connect } from 'react-redux'; import CategoriesList from './CategoriesList'; -import { getAllCategories } from '../store/rootReducer'; +import { getSettingsAppAllCategories } from '../../../app/store/rootReducer'; class AllCategoriesList extends React.Component { render () { @@ -30,7 +30,7 @@ class AllCategoriesList extends React.Component { } const mapStateToProps = state => ({ - categories: getAllCategories(state) + categories: getSettingsAppAllCategories(state) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/settings/components/App.js b/server/sonar-web/src/main/js/apps/settings/components/App.js index 9f2c99ecb6b..902e4bf4602 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/App.js +++ b/server/sonar-web/src/main/js/apps/settings/components/App.js @@ -27,7 +27,7 @@ import AllCategoriesList from './AllCategoriesList'; import GlobalMessagesContainer from './GlobalMessagesContainer'; import WildcardsHelp from './WildcardsHelp'; import { fetchSettings } from '../store/actions'; -import { getDefaultCategory } from '../store/rootReducer'; +import { getSettingsAppDefaultCategory } from '../../../app/store/rootReducer'; import '../styles.css'; type Props = { @@ -103,7 +103,7 @@ class App extends React.Component { } const mapStateToProps = state => ({ - defaultCategory: getDefaultCategory(state) + defaultCategory: getSettingsAppDefaultCategory(state) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/settings/components/AppContainer.js b/server/sonar-web/src/main/js/apps/settings/components/AppContainer.js new file mode 100644 index 00000000000..e4cd869edf9 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/settings/components/AppContainer.js @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import App from './App'; + +export default class AppContainer extends React.Component { + state = {}; + + componentDidMount () { + window.sonarqube.appStarted.then(options => + this.setState({ ready: true, component: options.component })); + } + + render () { + if (!this.state.ready) { + return null; + } + + return ( + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js b/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js index 5fb235d1da6..03b8f66ba75 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js +++ b/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js @@ -37,7 +37,7 @@ type Props = { }; export default class CategoriesList extends React.Component { - props: Props; + rops: Props; shouldComponentUpdate (nextProps: Props, nextState: ?{}) { return shallowCompare(this, nextProps, nextState); @@ -56,8 +56,10 @@ export default class CategoriesList extends React.Component { const className = category.key.toLowerCase() === this.props.selectedCategory.toLowerCase() ? 'active' : ''; + const pathname = this.props.component ? '/project/settings' : '/settings'; + return ( - + {category.name} ); diff --git a/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js b/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js index 8d7bf30fc1d..510cffb443a 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js +++ b/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js @@ -21,7 +21,7 @@ import React from 'react'; import { connect } from 'react-redux'; import SubCategoryDefinitionsList from './SubCategoryDefinitionsList'; -import { getSettingsForCategory } from '../store/rootReducer'; +import { getSettingsAppSettingsForCategory } from '../../../app/store/rootReducer'; class CategoryDefinitionsList extends React.Component { @@ -31,7 +31,7 @@ class CategoryDefinitionsList extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - settings: getSettingsForCategory(state, ownProps.category) + settings: getSettingsAppSettingsForCategory(state, ownProps.category) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/settings/components/Definition.js b/server/sonar-web/src/main/js/apps/settings/components/Definition.js index 065b6b447f4..0aa95078681 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/Definition.js +++ b/server/sonar-web/src/main/js/apps/settings/components/Definition.js @@ -28,10 +28,14 @@ import DefinitionChanges from './DefinitionChanges'; import { getPropertyName, getPropertyDescription, getSettingValue, isDefaultOrInherited } from '../utils'; import { translateWithParameters, translate } from '../../../helpers/l10n'; import { resetValue, saveValue } from '../store/actions'; -import { isLoading, getValidationMessage, getChangedValue } from '../store/rootReducer'; import { failValidation, passValidation } from '../store/settingsPage/validationMessages/actions'; import { cancelChange, changeValue } from '../store/settingsPage/changedValues/actions'; import { TYPE_PASSWORD } from '../constants'; +import { + getSettingsAppChangedValue, + isSettingsAppLoading, + getSettingsAppValidationMessage +} from '../../../app/store/rootReducer'; class Definition extends React.Component { mounted: boolean; @@ -186,9 +190,9 @@ class Definition extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - changedValue: getChangedValue(state, ownProps.setting.definition.key), - loading: isLoading(state, ownProps.setting.definition.key), - validationMessage: getValidationMessage(state, ownProps.setting.definition.key) + changedValue: getSettingsAppChangedValue(state, ownProps.setting.definition.key), + loading: isSettingsAppLoading(state, ownProps.setting.definition.key), + validationMessage: getSettingsAppValidationMessage(state, ownProps.setting.definition.key) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/settings/components/GlobalMessagesContainer.js b/server/sonar-web/src/main/js/apps/settings/components/GlobalMessagesContainer.js index da821b7d65f..9c9af651c6a 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/GlobalMessagesContainer.js +++ b/server/sonar-web/src/main/js/apps/settings/components/GlobalMessagesContainer.js @@ -20,10 +20,10 @@ // @flow import { connect } from 'react-redux'; import GlobalMessages from '../../../components/controls/GlobalMessages'; -import { getGlobalMessages } from '../store/rootReducer'; +import { getSettingsAppGlobalMessages } from '../../../app/store/rootReducer'; const mapStateToProps = state => ({ - messages: getGlobalMessages(state) + messages: getSettingsAppGlobalMessages(state) }); export default connect(mapStateToProps)(GlobalMessages); diff --git a/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionAppContainer.js b/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionAppContainer.js index 42bd05c788d..0dd8e051b67 100644 --- a/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionAppContainer.js +++ b/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionAppContainer.js @@ -20,9 +20,9 @@ import { connect } from 'react-redux'; import EncryptionApp from './EncryptionApp'; import { checkSecretKey, generateSecretKey, encryptValue, startGeneration } from '../store/encryptionPage/actions'; -import { getEncryptionState } from '../store/rootReducer'; +import { getSettingsAppEncryptionState } from '../../../app/store/rootReducer'; export default connect( - state => getEncryptionState(state), + state => getSettingsAppEncryptionState(state), { checkSecretKey, generateSecretKey, encryptValue, startGeneration } )(EncryptionApp); diff --git a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRowContainer.js b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRowContainer.js index af004df569f..0b8fefd5c39 100644 --- a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRowContainer.js +++ b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRowContainer.js @@ -19,11 +19,11 @@ */ import { connect } from 'react-redux'; import LicenseRow from './LicenseRow'; -import { getLicenseByKey } from '../store/rootReducer'; import { setLicense } from '../store/licenses/actions'; +import { getSettingsAppLicenseByKey } from '../../../app/store/rootReducer'; const mapStateToProps = (state, ownProps) => ({ - license: getLicenseByKey(state, ownProps.licenseKey) + license: getSettingsAppLicenseByKey(state, ownProps.licenseKey) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/settings/licenses/LicensesListContainer.js b/server/sonar-web/src/main/js/apps/settings/licenses/LicensesListContainer.js index bd692b7e390..ca19e0a2b41 100644 --- a/server/sonar-web/src/main/js/apps/settings/licenses/LicensesListContainer.js +++ b/server/sonar-web/src/main/js/apps/settings/licenses/LicensesListContainer.js @@ -20,10 +20,10 @@ import { connect } from 'react-redux'; import LicensesList from './LicensesList'; import { fetchLicenses } from '../store/licenses/actions'; -import { getAllLicenseKeys } from '../store/rootReducer'; +import { getSettingsAppAllLicenseKeys } from '../../../app/store/rootReducer'; const mapStateToProps = state => ({ - licenses: getAllLicenseKeys(state) + licenses: getSettingsAppAllLicenseKeys(state) }); export default connect( diff --git a/server/sonar-web/src/main/js/apps/settings/routes.js b/server/sonar-web/src/main/js/apps/settings/routes.js new file mode 100644 index 00000000000..1982da9b7aa --- /dev/null +++ b/server/sonar-web/src/main/js/apps/settings/routes.js @@ -0,0 +1,33 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute, Route, Redirect } from 'react-router'; +import AppContainer from './components/AppContainer'; +import LicensesApp from './licenses/LicensesApp'; +import EncryptionAppContainer from './encryption/EncryptionAppContainer'; +import ServerIdAppContainer from './serverId/ServerIdAppContainer'; + +export default [ + , + , + , + , + +]; 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 df6ed194049..79f4d15ed9c 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 @@ -25,9 +25,9 @@ import { parseError } from '../../code/utils'; import { addGlobalErrorMessage, closeAllGlobalMessages } from '../../../components/store/globalMessages'; import { passValidation, failValidation } from './settingsPage/validationMessages/actions'; import { cancelChange } from './settingsPage/changedValues/actions'; -import { getDefinition, getChangedValue } from './rootReducer'; import { isEmptyValue } from '../utils'; import { translate } from '../../../helpers/l10n'; +import { getSettingsAppDefinition, getSettingsAppChangedValue } from '../../../app/store/rootReducer'; export const fetchSettings = componentKey => dispatch => { return getDefinitions(componentKey) @@ -48,8 +48,8 @@ export const saveValue = (key, componentKey) => (dispatch, getState) => { dispatch(startLoading(key)); const state = getState(); - const definition = getDefinition(state, key); - const value = getChangedValue(state, key); + const definition = getSettingsAppDefinition(state, key); + const value = getSettingsAppChangedValue(state, key); if (isEmptyValue(definition, value)) { dispatch(failValidation(key, translate('settings.state.value_cant_be_empty'))); diff --git a/server/sonar-web/src/main/js/apps/system/app.js b/server/sonar-web/src/main/js/apps/system/app.js deleted file mode 100644 index 652fd6d06bc..00000000000 --- a/server/sonar-web/src/main/js/apps/system/app.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import ReactDOM from 'react-dom'; -import Main from './main'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - ReactDOM.render(
        , el); -}); - diff --git a/server/sonar-web/src/main/js/apps/system/routes.js b/server/sonar-web/src/main/js/apps/system/routes.js new file mode 100644 index 00000000000..9d257927d7f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/system/routes.js @@ -0,0 +1,27 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute, Redirect } from 'react-router'; +import Main from './main'; + +export default [ + , + +]; diff --git a/server/sonar-web/src/main/js/apps/update-center/app.js b/server/sonar-web/src/main/js/apps/update-center/app.js deleted file mode 100644 index 3cf3adc9d38..00000000000 --- a/server/sonar-web/src/main/js/apps/update-center/app.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 Backbone from 'backbone'; -import Marionette from 'backbone.marionette'; -import Layout from './layout'; -import HeaderView from './header-view'; -import SearchView from './search-view'; -import ListView from './list-view'; -import FooterView from './footer-view'; -import Controller from './controller'; -import Router from './router'; -import Plugins from './plugins'; - -const App = new Marionette.Application(); -const init = function () { - const options = window.sonarqube; - - // State - this.state = new Backbone.Model({ - updateCenterActive: window.SS.updateCenterActive - }); - - // Layout - this.layout = new Layout({ el: options.el }); - this.layout.render(); - - // Plugins - this.plugins = new Plugins(); - - // Controller - this.controller = new Controller({ collection: this.plugins, state: this.state }); - - // Router - this.router = new Router({ controller: this.controller }); - - // Header - this.headerView = new HeaderView({ collection: this.plugins }); - this.layout.headerRegion.show(this.headerView); - - // Search - this.searchView = new SearchView({ collection: this.plugins, router: this.router, state: this.state }); - this.layout.searchRegion.show(this.searchView); - this.searchView.focusSearch(); - - // List - this.listView = new ListView({ collection: this.plugins }); - this.layout.listRegion.show(this.listView); - - // Footer - this.footerView = new FooterView({ collection: this.plugins }); - this.layout.footerRegion.show(this.footerView); - - // Go - Backbone.history.start({ - pushState: true, - root: options.urlRoot - }); -}; - -App.on('start', function () { - init.call(App); -}); - -window.sonarqube.appStarted.then(options => App.start(options)); - diff --git a/server/sonar-web/src/main/js/apps/update-center/components/UpdateCenterAppContainer.js b/server/sonar-web/src/main/js/apps/update-center/components/UpdateCenterAppContainer.js new file mode 100644 index 00000000000..4e40999fe81 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/update-center/components/UpdateCenterAppContainer.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import init from '../init'; + +export default class UpdateCenterAppContainer extends React.Component { + componentDidMount () { + init(this.refs.container); + } + + render () { + return
        ; + } +} diff --git a/server/sonar-web/src/main/js/apps/update-center/init.js b/server/sonar-web/src/main/js/apps/update-center/init.js new file mode 100644 index 00000000000..3c509e36232 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/update-center/init.js @@ -0,0 +1,81 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 Backbone from 'backbone'; +import Marionette from 'backbone.marionette'; +import Layout from './layout'; +import HeaderView from './header-view'; +import SearchView from './search-view'; +import ListView from './list-view'; +import FooterView from './footer-view'; +import Controller from './controller'; +import Router from './router'; +import Plugins from './plugins'; + +const App = new Marionette.Application(); +const init = function (el) { + // State + this.state = new Backbone.Model({ + updateCenterActive: window.SS.updateCenterActive + }); + + // Layout + this.layout = new Layout({ el }); + this.layout.render(); + + // Plugins + this.plugins = new Plugins(); + + // Controller + this.controller = new Controller({ collection: this.plugins, state: this.state }); + + // Router + this.router = new Router({ controller: this.controller }); + + // Header + this.headerView = new HeaderView({ collection: this.plugins }); + this.layout.headerRegion.show(this.headerView); + + // Search + this.searchView = new SearchView({ collection: this.plugins, router: this.router, state: this.state }); + this.layout.searchRegion.show(this.searchView); + this.searchView.focusSearch(); + + // List + this.listView = new ListView({ collection: this.plugins }); + this.layout.listRegion.show(this.listView); + + // Footer + this.footerView = new FooterView({ collection: this.plugins }); + this.layout.footerRegion.show(this.footerView); + + // Go + Backbone.history.start({ + pushState: true, + root: window.baseUrl + '/updatecenter' + }); +}; + +App.on('start', function (el) { + init.call(App, el); +}); + +export default function (el) { + App.start(el); +} diff --git a/server/sonar-web/src/main/js/apps/update-center/routes.js b/server/sonar-web/src/main/js/apps/update-center/routes.js new file mode 100644 index 00000000000..308a3fa8538 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/update-center/routes.js @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute, Route } from 'react-router'; +import UpdateCenterAppContainer from './components/UpdateCenterAppContainer'; + +export default [ + , + , + , + , + +]; diff --git a/server/sonar-web/src/main/js/apps/users/app.js b/server/sonar-web/src/main/js/apps/users/app.js deleted file mode 100644 index 14ea47e63e3..00000000000 --- a/server/sonar-web/src/main/js/apps/users/app.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 Marionette from 'backbone.marionette'; - -import Layout from './layout'; -import Users from './users'; -import HeaderView from './header-view'; -import SearchView from './search-view'; -import ListView from './list-view'; -import ListFooterView from './list-footer-view'; -import { getIdentityProviders } from '../../api/users'; - -const App = new Marionette.Application(); - -const init = function (providers) { - const options = window.sonarqube; - - // Layout - this.layout = new Layout({ el: options.el }); - this.layout.render(); - - // Collection - this.users = new Users(); - - // Header View - this.headerView = new HeaderView({ collection: this.users }); - this.layout.headerRegion.show(this.headerView); - - // Search View - this.searchView = new SearchView({ collection: this.users }); - this.layout.searchRegion.show(this.searchView); - - // List View - this.listView = new ListView({ collection: this.users, providers }); - this.layout.listRegion.show(this.listView); - - // List Footer View - this.listFooterView = new ListFooterView({ collection: this.users }); - this.layout.listFooterRegion.show(this.listFooterView); - - // Go! - this.users.fetch(); -}; - -App.on('start', function () { - getIdentityProviders().then(r => init.call(App, r.identityProviders)); -}); - -window.sonarqube.appStarted.then(options => App.start(options)); - diff --git a/server/sonar-web/src/main/js/apps/users/components/UsersAppContainer.js b/server/sonar-web/src/main/js/apps/users/components/UsersAppContainer.js new file mode 100644 index 00000000000..8442a308327 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/users/components/UsersAppContainer.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import init from '../init'; + +export default class UsersAppContainer extends React.Component { + componentDidMount () { + init(this.refs.container); + } + + render () { + return
        ; + } +} diff --git a/server/sonar-web/src/main/js/apps/users/init.js b/server/sonar-web/src/main/js/apps/users/init.js new file mode 100644 index 00000000000..cd1dc8a6568 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/users/init.js @@ -0,0 +1,66 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 Marionette from 'backbone.marionette'; + +import Layout from './layout'; +import Users from './users'; +import HeaderView from './header-view'; +import SearchView from './search-view'; +import ListView from './list-view'; +import ListFooterView from './list-footer-view'; +import { getIdentityProviders } from '../../api/users'; + +const App = new Marionette.Application(); + +const init = function (el, providers) { + // Layout + this.layout = new Layout({ el }); + this.layout.render(); + + // Collection + this.users = new Users(); + + // Header View + this.headerView = new HeaderView({ collection: this.users }); + this.layout.headerRegion.show(this.headerView); + + // Search View + this.searchView = new SearchView({ collection: this.users }); + this.layout.searchRegion.show(this.searchView); + + // List View + this.listView = new ListView({ collection: this.users, providers }); + this.layout.listRegion.show(this.listView); + + // List Footer View + this.listFooterView = new ListFooterView({ collection: this.users }); + this.layout.listFooterRegion.show(this.listFooterView); + + // Go! + this.users.fetch(); +}; + +App.on('start', function (el) { + getIdentityProviders().then(r => init.call(App, el, r.identityProviders)); +}); + +export default function (el) { + App.start(el); +} diff --git a/server/sonar-web/src/main/js/apps/users/routes.js b/server/sonar-web/src/main/js/apps/users/routes.js new file mode 100644 index 00000000000..b727131f339 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/users/routes.js @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute } from 'react-router'; +import UsersAppContainer from './components/UsersAppContainer'; + +export default ( + +); diff --git a/server/sonar-web/src/main/js/apps/web-api/app.js b/server/sonar-web/src/main/js/apps/web-api/app.js deleted file mode 100644 index 0ff00d28a30..00000000000 --- a/server/sonar-web/src/main/js/apps/web-api/app.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { render } from 'react-dom'; -import { Router, Route, Redirect, useRouterHistory } from 'react-router'; -import { createHistory } from 'history'; - -import WebApiApp from './components/WebApiApp'; -import './styles/web-api.css'; - -window.sonarqube.appStarted.then(options => { - const el = document.querySelector(options.el); - - const history = useRouterHistory(createHistory)({ - basename: window.sonarqube.urlRoot - }); - - render(( - - - - - ), el); -}); diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Action.js b/server/sonar-web/src/main/js/apps/web-api/components/Action.js index 2c3cc0dcfa2..cfe3a6df465 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/Action.js +++ b/server/sonar-web/src/main/js/apps/web-api/components/Action.js @@ -60,7 +60,7 @@ export default class Action extends React.Component {

        diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Menu.js b/server/sonar-web/src/main/js/apps/web-api/components/Menu.js index af81e50fb45..198fd6cc5f3 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/Menu.js +++ b/server/sonar-web/src/main/js/apps/web-api/components/Menu.js @@ -50,7 +50,7 @@ export default function Menu ({ domains, showInternal, showOnlyDeprecated, searc + to={'/web_api/' + domain.path}>

        {domain.path} {domain.internal && ( diff --git a/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js b/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js index 51c56ab4839..ab5dfebbf23 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js +++ b/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js @@ -24,6 +24,7 @@ import Menu from './Menu'; import Search from './Search'; import Domain from './Domain'; import { getActionKey, isDomainPathActive } from '../utils'; +import '../styles/web-api.css'; export default class WebApiApp extends React.Component { state = { @@ -59,7 +60,7 @@ export default class WebApiApp extends React.Component { } scrollToAction () { - const { splat } = this.props.params; + const splat = this.props.params.splat || ''; this.scrollToElement(splat); } @@ -77,7 +78,7 @@ export default class WebApiApp extends React.Component { } toggleInternalInitially () { - const { splat } = this.props.params; + const splat = this.props.params.splat || ''; const { domains, showInternal } = this.state; if (!showInternal) { @@ -100,7 +101,7 @@ export default class WebApiApp extends React.Component { } handleToggleInternal () { - const { splat } = this.props.params; + const splat = this.props.params.splat || ''; const { router } = this.context; const { domains } = this.state; const domain = domains.find(domain => isDomainPathActive(domain.path, splat)); @@ -118,7 +119,7 @@ export default class WebApiApp extends React.Component { } render () { - const { splat } = this.props.params; + const splat = this.props.params.splat || ''; const { domains, showInternal, showOnlyDeprecated, searchQuery } = this.state; const domain = domains.find(domain => isDomainPathActive(domain.path, splat)); @@ -127,7 +128,7 @@ export default class WebApiApp extends React.Component {
        - +

        Web API

        diff --git a/server/sonar-web/src/main/js/apps/web-api/routes.js b/server/sonar-web/src/main/js/apps/web-api/routes.js new file mode 100644 index 00000000000..18daa8ccd71 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/web-api/routes.js @@ -0,0 +1,27 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { IndexRoute, Route } from 'react-router'; +import WebApiApp from './components/WebApiApp'; + +export default [ + , + +]; diff --git a/server/sonar-web/src/main/js/main/app.js b/server/sonar-web/src/main/js/main/app.js deleted file mode 100644 index 0fe3aa0765b..00000000000 --- a/server/sonar-web/src/main/js/main/app.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 $ from 'jquery'; -import _ from 'underscore'; -import Backbone from 'backbone'; -import moment from 'moment'; -import './processes'; -import Navigation from './nav/app'; -import { installGlobal, requestMessages } from '../helpers/l10n'; -import * as measures from '../helpers/measures'; -import * as request from '../helpers/request'; -import './common-styles'; - -import '../../less/sonar.less'; - -// set the Backbone's $ -Backbone.$ = $; - -function requestLocalizationBundle () { - if (!window.sonarqube.bannedNavigation) { - installGlobal(); - return requestMessages(); - } else { - return Promise.resolve(); - } -} - -function startNavigation () { - if (!window.sonarqube.bannedNavigation) { - return new Navigation().start(); - } else { - return Promise.resolve(); - } -} - -function prepareAppOptions (navResponse) { - const appOptions = { el: '#content' }; - if (navResponse) { - appOptions.rootQualifiers = navResponse.global.qualifiers; - appOptions.logoUrl = navResponse.global.logoUrl; - appOptions.logoWidth = navResponse.global.logoWidth; - if (navResponse.component) { - appOptions.component = { - id: navResponse.component.uuid, - key: navResponse.component.key, - name: navResponse.component.name, - qualifier: _.last(navResponse.component.breadcrumbs).qualifier, - breadcrumbs: navResponse.component.breadcrumbs, - snapshotDate: navResponse.component.snapshotDate - }; - } - } - return appOptions; -} - -function getPreferredLanguage () { - return window.navigator.languages ? window.navigator.languages[0] : window.navigator.language; -} - -moment.locale(getPreferredLanguage()); - -window.sonarqube.appStarted = Promise.resolve() - .then(requestLocalizationBundle) - .then(startNavigation) - .then(prepareAppOptions); - -window.SonarMeasures = measures; -window.SonarRequest = request; diff --git a/server/sonar-web/src/main/js/main/common-styles.js b/server/sonar-web/src/main/js/main/common-styles.js deleted file mode 100644 index cf26f70de29..00000000000 --- a/server/sonar-web/src/main/js/main/common-styles.js +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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. - */ - -// this is a bad idea -// TODO rework once we have single js app - -import '../components/ui/Level.css'; -import '../components/ui/Rating.css'; diff --git a/server/sonar-web/src/main/js/main/nav/__tests__/nav-test.js b/server/sonar-web/src/main/js/main/nav/__tests__/nav-test.js deleted file mode 100644 index d5ddbab8afd..00000000000 --- a/server/sonar-web/src/main/js/main/nav/__tests__/nav-test.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { shallow } from 'enzyme'; -import ComponentNavBreadcrumbs from '../component/component-nav-breadcrumbs'; - -describe('ComponentNavBreadcrumbs', () => { - it('should not render breadcrumbs with one element', function () { - const breadcrumbs = [{ key: 'my-project', name: 'My Project', qualifier: 'TRK' }]; - const result = shallow(); - expect(result.find('li').length).toBe(1); - expect(result.find('a').length).toBe(1); - }); -}); diff --git a/server/sonar-web/src/main/js/main/nav/app.js b/server/sonar-web/src/main/js/main/nav/app.js deleted file mode 100644 index 902e6ea07ef..00000000000 --- a/server/sonar-web/src/main/js/main/nav/app.js +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 _ from 'underscore'; -import React from 'react'; -import ReactDOM from 'react-dom'; - -import GlobalNav from './global/global-nav'; -import ComponentNav from './component/component-nav'; -import SettingsNav from './settings/settings-nav'; -import { getGlobalNavigation, getComponentNavigation, getSettingsNavigation } from '../../api/nav'; - -export default class App { - start () { - const options = window.sonarqube; - - require('../../components/workspace/main'); - - return new Promise((resolve) => { - const response = {}; - const requests = []; - - requests.push( - App.renderGlobalNav(options).then(r => response.global = r) - ); - - if (options.space === 'component') { - requests.push( - App.renderComponentNav(options).then(r => response.component = r) - ); - } else if (options.space === 'settings') { - requests.push( - App.renderSettingsNav(options).then(r => response.settings = r) - ); - } - - Promise.all(requests).then(() => resolve(response)); - }); - } - - static renderGlobalNav (options) { - return getGlobalNavigation().then(r => { - const el = document.getElementById('global-navigation'); - if (el) { - ReactDOM.render(, el); - } - return r; - }); - } - - static renderComponentNav (options) { - return getComponentNavigation(options.componentKey).then(component => { - const el = document.getElementById('context-navigation'); - const nextComponent = { - ...component, - qualifier: _.last(component.breadcrumbs).qualifier - }; - if (el) { - ReactDOM.render(, el); - } - return component; - }); - } - - static renderSettingsNav (options) { - return getSettingsNavigation().then(r => { - const el = document.getElementById('context-navigation'); - const opts = _.extend(r, options); - if (el) { - ReactDOM.render(, el); - } - return r; - }); - } -} diff --git a/server/sonar-web/src/main/js/main/nav/component/RecentHistory.js b/server/sonar-web/src/main/js/main/nav/component/RecentHistory.js deleted file mode 100644 index 6454cfe8afb..00000000000 --- a/server/sonar-web/src/main/js/main/nav/component/RecentHistory.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 _ from 'underscore'; - -const STORAGE_KEY = 'sonar_recent_history'; -const HISTORY_LIMIT = 10; - -export default class RecentHistory { - static get () { - let history = localStorage.getItem(STORAGE_KEY); - if (history == null) { - history = []; - } else { - try { - history = JSON.parse(history); - } catch (e) { - RecentHistory.clear(); - history = []; - } - } - return history; - } - - static set (newHistory) { - localStorage.setItem(STORAGE_KEY, JSON.stringify(newHistory)); - } - - static clear () { - localStorage.removeItem(STORAGE_KEY); - } - - static add (componentKey, componentName, icon) { - const sonarHistory = RecentHistory.get(); - - if (componentKey) { - const newEntry = { key: componentKey, name: componentName, icon }; - let newHistory = _.reject(sonarHistory, entry => entry.key === newEntry.key); - newHistory.unshift(newEntry); - newHistory = _.first(newHistory, HISTORY_LIMIT); - RecentHistory.set(newHistory); - } - } - - static remove (componentKey) { - const history = RecentHistory.get(); - const newHistory = _.reject(history, entry => entry.key === componentKey); - RecentHistory.set(newHistory); - } -} diff --git a/server/sonar-web/src/main/js/main/nav/component/component-nav-breadcrumbs.js b/server/sonar-web/src/main/js/main/nav/component/component-nav-breadcrumbs.js deleted file mode 100644 index 0b71555ad81..00000000000 --- a/server/sonar-web/src/main/js/main/nav/component/component-nav-breadcrumbs.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import QualifierIcon from '../../../components/shared/qualifier-icon'; - -export default React.createClass({ - render() { - if (!this.props.breadcrumbs) { - return null; - } - const items = this.props.breadcrumbs.map((item, index) => { - const url = `${window.baseUrl}/dashboard/index?id=${encodeURIComponent(item.key)}`; - return ( -
      • - -  {item.name} - -
      • - ); - }); - return ( -
          {items}
        - ); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/component/component-nav-favorite.js b/server/sonar-web/src/main/js/main/nav/component/component-nav-favorite.js deleted file mode 100644 index b3d68193b48..00000000000 --- a/server/sonar-web/src/main/js/main/nav/component/component-nav-favorite.js +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import Favorite from '../../../components/controls/Favorite'; - -export default React.createClass({ - render() { - if (!this.props.canBeFavorite) { - return null; - } - return ( -
        - -
        - ); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/component/component-nav-menu.js b/server/sonar-web/src/main/js/main/nav/component/component-nav-menu.js deleted file mode 100644 index 50525635834..00000000000 --- a/server/sonar-web/src/main/js/main/nav/component/component-nav-menu.js +++ /dev/null @@ -1,262 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 qs from 'querystring'; -import classNames from 'classnames'; -import React from 'react'; -import LinksMixin from '../links-mixin'; -import { translate } from '../../../helpers/l10n'; -import { getComponentUrl } from '../../../helpers/urls'; - -const SETTINGS_URLS = [ - '/project/settings', - '/project/quality_profiles', - '/project/quality_gate', - '/custom_measures', - '/project/links', - '/project_roles', - '/project/history', - 'background_tasks', - '/project/key', - '/project/deletion' -]; - -export default React.createClass({ - mixins: [LinksMixin], - - isDeveloper() { - return this.props.component.qualifier === 'DEV'; - }, - - isView() { - const { qualifier } = this.props.component; - return qualifier === 'VW' || qualifier === 'SVW'; - }, - - periodParameter() { - const params = qs.parse(window.location.search.substr(1)); - return params.period ? `&period=${params.period}` : ''; - }, - - getPeriod() { - const params = qs.parse(window.location.search.substr(1)); - return params.period; - }, - - isFixedDashboardActive() { - const path = window.location.pathname; - return path.indexOf(window.baseUrl + '/dashboard') === 0 || path.indexOf(window.baseUrl + '/governance') === 0; - }, - - renderDashboardLink() { - const url = getComponentUrl(this.props.component.key); - const name = ; - const className = classNames({ active: this.isFixedDashboardActive() }); - return ( -
      • - {name} -
      • - ); - }, - - renderCodeLink() { - if (this.isDeveloper()) { - return null; - } - - const url = `/code/?id=${encodeURIComponent(this.props.component.key)}`; - const header = this.isView() ? translate('view_projects.page') : translate('code.page'); - return this.renderLink(url, header, '/code'); - }, - - renderComponentIssuesLink() { - const url = `/component_issues/index?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('issues.page'), '/component_issues'); - }, - - renderComponentMeasuresLink() { - const url = `/component_measures/?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('layout.measures'), '/component_measures'); - }, - - renderAdministration() { - const shouldShowAdministration = - this.props.conf.showBackgroundTasks || - this.props.conf.showHistory || - this.props.conf.showLinks || - this.props.conf.showManualMeasures || - this.props.conf.showPermissions || - this.props.conf.showQualityGates || - this.props.conf.showQualityProfiles || - this.props.conf.showSettings || - this.props.conf.showUpdateKey; - if (!shouldShowAdministration) { - return null; - } - const isSettingsActive = SETTINGS_URLS.some(url => { - return window.location.href.indexOf(url) !== -1; - }); - const className = 'dropdown' + (isSettingsActive ? ' active' : ''); - return ( -
      • - - {translate('layout.settings')}  - - -
          - {this.renderSettingsLink()} - {this.renderProfilesLink()} - {this.renderQualityGateLink()} - {this.renderCustomMeasuresLink()} - {this.renderLinksLink()} - {this.renderPermissionsLink()} - {this.renderHistoryLink()} - {this.renderBackgroundTasksLink()} - {this.renderUpdateKeyLink()} - {this.renderExtensions()} - {this.renderDeletionLink()} -
        -
      • - ); - }, - - renderSettingsLink() { - if (!this.props.conf.showSettings) { - return null; - } - const url = `/project/settings?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('project_settings.page'), '/project/settings'); - }, - - renderProfilesLink() { - if (!this.props.conf.showQualityProfiles) { - return null; - } - const url = `/project/quality_profiles?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('project_quality_profiles.page'), '/project/quality_profiles'); - }, - - renderQualityGateLink() { - if (!this.props.conf.showQualityGates) { - return null; - } - const url = `/project/quality_gate?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('project_quality_gate.page'), '/project/quality_gate'); - }, - - renderCustomMeasuresLink() { - if (!this.props.conf.showManualMeasures) { - return null; - } - const url = `/custom_measures?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('custom_measures.page'), '/custom_measures'); - }, - - renderLinksLink() { - if (!this.props.conf.showLinks) { - return null; - } - const url = `/project/links?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('project_links.page'), '/project/links'); - }, - - renderPermissionsLink() { - if (!this.props.conf.showPermissions) { - return null; - } - const url = `/project_roles?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('permissions.page'), '/project_roles'); - }, - - renderHistoryLink() { - if (!this.props.conf.showHistory) { - return null; - } - const url = `/project/history?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('project_history.page'), '/project/history'); - }, - - renderBackgroundTasksLink() { - if (!this.props.conf.showBackgroundTasks) { - return null; - } - const url = `/project/background_tasks?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('background_tasks.page'), '/project/background_tasks'); - }, - - renderUpdateKeyLink() { - if (!this.props.conf.showUpdateKey) { - return null; - } - const url = `/project/key?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('update_key.page'), '/project/key'); - }, - - renderDeletionLink() { - const { qualifier } = this.props.component; - - if (qualifier !== 'TRK' && qualifier !== 'VW') { - return null; - } - - const url = `/project/deletion?id=${encodeURIComponent(this.props.component.key)}`; - return this.renderLink(url, translate('deletion.page'), '/project/deletion'); - }, - - renderExtensions() { - const extensions = this.props.conf.extensions || []; - return extensions.map(e => this.renderLink(e.url, e.name, e.url)); - }, - - renderTools() { - const extensions = this.props.component.extensions || []; - const withoutGovernance = extensions.filter(ext => ext.name !== 'Governance'); - const tools = withoutGovernance - .map(extension => this.renderLink(extension.url, extension.name)); - - if (!tools.length) { - return null; - } - - return ( -
      • - - {translate('more')}  - - -
          - {tools} -
        -
      • - ); - }, - - render() { - return ( -
          - {this.renderDashboardLink()} - {this.renderComponentIssuesLink()} - {this.renderComponentMeasuresLink()} - {this.renderCodeLink()} - {this.renderTools()} - {this.renderAdministration()} -
        - ); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/component/component-nav-meta.js b/server/sonar-web/src/main/js/main/nav/component/component-nav-meta.js deleted file mode 100644 index fddc39b98c5..00000000000 --- a/server/sonar-web/src/main/js/main/nav/component/component-nav-meta.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 moment from 'moment'; -import React from 'react'; -import PendingIcon from '../../../components/shared/pending-icon'; -import { translate, translateWithParameters } from '../../../helpers/l10n'; - -export default React.createClass({ - render() { - const metaList = []; - const canSeeBackgroundTasks = this.props.conf.showBackgroundTasks; - const backgroundTasksUrl = - `${window.baseUrl}/project/background_tasks?id=${encodeURIComponent(this.props.component.key)}`; - - if (this.props.isInProgress) { - const tooltip = canSeeBackgroundTasks ? - translateWithParameters('component_navigation.status.in_progress.admin', backgroundTasksUrl) : - translate('component_navigation.status.in_progress'); - metaList.push( -
      • - - {' '} - {translate('background_task.status.IN_PROGRESS')} -
      • - ); - } else if (this.props.isPending) { - const tooltip = canSeeBackgroundTasks ? - translateWithParameters('component_navigation.status.pending.admin', backgroundTasksUrl) : - translate('component_navigation.status.pending'); - metaList.push( -
      • - {translate('background_task.status.PENDING')} -
      • - ); - } else if (this.props.isFailed) { - const tooltip = canSeeBackgroundTasks ? - translateWithParameters('component_navigation.status.failed.admin', backgroundTasksUrl) : - translate('component_navigation.status.failed'); - metaList.push( -
      • - {translate('background_task.status.FAILED')} -
      • - ); - } - - if (this.props.snapshotDate) { - metaList.push(
      • {moment(this.props.snapshotDate).format('LLL')}
      • ); - } - - if (this.props.version) { - metaList.push(
      • Version {this.props.version}
      • ); - } - - return ( -
        -
          {metaList}
        -
        - ); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/component/component-nav.js b/server/sonar-web/src/main/js/main/nav/component/component-nav.js deleted file mode 100644 index 7e950e515db..00000000000 --- a/server/sonar-web/src/main/js/main/nav/component/component-nav.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 $ from 'jquery'; -import _ from 'underscore'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import { STATUSES } from '../../../apps/background-tasks/constants'; -import { getTasksForComponent } from '../../../api/ce'; -import ComponentNavFavorite from './component-nav-favorite'; -import ComponentNavBreadcrumbs from './component-nav-breadcrumbs'; -import ComponentNavMeta from './component-nav-meta'; -import ComponentNavMenu from './component-nav-menu'; -import RecentHistory from './RecentHistory'; - -export default React.createClass({ - componentDidMount() { - this.loadStatus(); - this.populateRecentHistory(); - }, - - loadStatus() { - getTasksForComponent(this.props.component.uuid).then(r => { - this.setState({ - isPending: !!_.findWhere(r.queue, { status: STATUSES.PENDING }), - isInProgress: !!_.findWhere(r.queue, { status: STATUSES.IN_PROGRESS }), - isFailed: r.current && r.current.status === STATUSES.FAILED - }, this.initTooltips); - }); - }, - - populateRecentHistory() { - const qualifier = _.last(this.props.component.breadcrumbs).qualifier; - if (['TRK', 'VW', 'DEV'].indexOf(qualifier) !== -1) { - RecentHistory.add(this.props.component.key, this.props.component.name, qualifier.toLowerCase()); - } - }, - - initTooltips() { - $('[data-toggle="tooltip"]', ReactDOM.findDOMNode(this)).tooltip({ - container: 'body', - placement: 'bottom', - delay: { show: 0, hide: 2000 }, - html: true - }); - }, - - render() { - return ( -
        - - - - - - - -
        - ); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/dashboard-name-mixin.js b/server/sonar-web/src/main/js/main/nav/dashboard-name-mixin.js deleted file mode 100644 index 8ec177c23cb..00000000000 --- a/server/sonar-web/src/main/js/main/nav/dashboard-name-mixin.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 { translate } from '../../helpers/l10n'; - -export default { - getLocalizedDashboardName(baseName) { - const l10nKey = `dashboard.${baseName}.name`; - const l10nLabel = translate(l10nKey); - if (l10nLabel !== l10nKey) { - return l10nLabel; - } else { - return baseName; - } - } -}; diff --git a/server/sonar-web/src/main/js/main/nav/global/global-nav-branding.js b/server/sonar-web/src/main/js/main/nav/global/global-nav-branding.js deleted file mode 100644 index 88a8b038bb7..00000000000 --- a/server/sonar-web/src/main/js/main/nav/global/global-nav-branding.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import { translate } from '../../../helpers/l10n'; - -export default React.createClass({ - renderLogo() { - const url = this.props.logoUrl || `${window.baseUrl}/images/logo.svg`; - const width = this.props.logoWidth || 100; - const height = 30; - const title = translate('layout.sonar.slogan'); - return {title}; - }, - - render() { - const homeController = window.SS.user ? '/projects/favorite' : '/about'; - const homeUrl = window.baseUrl + homeController; - const homeLinkClassName = 'navbar-brand' + (this.props.logoUrl ? ' navbar-brand-custom' : ''); - return ( - - ); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/global/global-nav-menu.js b/server/sonar-web/src/main/js/main/nav/global/global-nav-menu.js deleted file mode 100644 index 7d25c1b1a25..00000000000 --- a/server/sonar-web/src/main/js/main/nav/global/global-nav-menu.js +++ /dev/null @@ -1,131 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import DashboardNameMixin from '../dashboard-name-mixin'; -import LinksMixin from '../links-mixin'; -import { translate } from '../../../helpers/l10n'; - -export default React.createClass({ - mixins: [DashboardNameMixin, LinksMixin], - - getDefaultProps () { - return { globalDashboards: [], globalPages: [] }; - }, - - renderProjects () { - const controller = window.SS.user ? '/projects/favorite' : '/projects'; - const url = window.baseUrl + controller; - return ( -
      • - {translate('projects.page')} -
      • - ); - }, - - renderIssuesLink () { - const query = window.SS.user ? '#resolved=false|assigned_to_me=true' : '#resolved=false'; - const url = window.baseUrl + '/issues' + query; - return ( -
      • - {translate('issues.page')} -
      • - ); - }, - - renderRulesLink () { - const url = window.baseUrl + '/coding_rules'; - return ( -
      • - {translate('coding_rules.page')} -
      • - ); - }, - - renderProfilesLink() { - const url = window.baseUrl + '/profiles'; - return ( -
      • - {translate('quality_profiles.page')} -
      • - ); - }, - - renderQualityGatesLink () { - const url = window.baseUrl + '/quality_gates'; - return ( -
      • - {translate('quality_gates.page')} -
      • - ); - }, - - renderAdministrationLink () { - if (!window.SS.isUserAdmin) { - return null; - } - const url = window.baseUrl + '/settings'; - return ( -
      • - {translate('layout.settings')} -
      • - ); - }, - - renderGlobalPageLink (globalPage, index) { - const url = window.baseUrl + globalPage.url; - return ( -
      • - {globalPage.name} -
      • - ); - }, - - renderMore () { - if (this.props.globalPages.length === 0) { - return null; - } - const globalPages = this.props.globalPages.map(this.renderGlobalPageLink); - return ( -
      • - - {translate('more')}  - - -
          - {globalPages} -
        -
      • - ); - }, - - render () { - return ( -
          - {this.renderProjects()} - {this.renderIssuesLink()} - {this.renderRulesLink()} - {this.renderProfilesLink()} - {this.renderQualityGatesLink()} - {this.renderAdministrationLink()} - {this.renderMore()} -
        - ); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/global/global-nav-search.js b/server/sonar-web/src/main/js/main/nav/global/global-nav-search.js deleted file mode 100644 index e84850bf365..00000000000 --- a/server/sonar-web/src/main/js/main/nav/global/global-nav-search.js +++ /dev/null @@ -1,106 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 Backbone from 'backbone'; -import React from 'react'; -import SearchView from './search-view'; - -function contains (root, node) { - while (node) { - if (node === root) { - return true; - } - node = node.parentNode; - } - return false; -} - -export default React.createClass({ - getInitialState() { - return { open: false }; - }, - - componentDidMount() { - key('s', () => { - const isModalOpen = document.querySelector('html').classList.contains('modal-open'); - if (!isModalOpen) { - this.openSearch(); - } - return false; - }); - }, - - componentWillUnmount() { - this.closeSearch(); - key.unbind('s'); - }, - - openSearch() { - document.addEventListener('click', this.onClickOutside); - this.setState({ open: true }, this.renderSearchView); - }, - - closeSearch() { - document.removeEventListener('click', this.onClickOutside); - this.resetSearchView(); - this.setState({ open: false }); - }, - - renderSearchView() { - const searchContainer = this.refs.container; - this.searchView = new SearchView({ - model: new Backbone.Model(this.props), - hide: this.closeSearch - }); - this.searchView.render().$el.appendTo(searchContainer); - }, - - resetSearchView() { - if (this.searchView) { - this.searchView.destroy(); - } - }, - - onClick(e) { - e.preventDefault(); - if (this.state.open) { - this.closeSearch(); - } else { - this.openSearch(); - } - }, - - onClickOutside(e) { - if (!contains(this.refs.dropdown, e.target)) { - this.closeSearch(); - } - }, - - render() { - const dropdownClassName = 'dropdown' + (this.state.open ? ' open' : ''); - return ( -
      • - -   - -
        -
      • - ); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/global/global-nav-user.js b/server/sonar-web/src/main/js/main/nav/global/global-nav-user.js deleted file mode 100644 index 8068fae02a9..00000000000 --- a/server/sonar-web/src/main/js/main/nav/global/global-nav-user.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import Avatar from '../../../components/ui/Avatar'; -import RecentHistory from '../component/RecentHistory'; -import { translate } from '../../../helpers/l10n'; - -export default React.createClass({ - renderAuthenticated() { - return ( -
      • - -   - {window.SS.userName}  - - -
      • - ); - }, - - renderAnonymous() { - return ( -
      • - {translate('layout.login')} -
      • - ); - }, - - handleLogin(e) { - e.preventDefault(); - const returnTo = window.location.pathname + window.location.search; - window.location = `${window.baseUrl}/sessions/new?return_to=${encodeURIComponent(returnTo)}${window.location.hash}`; - }, - - handleLogout(e) { - e.preventDefault(); - RecentHistory.clear(); - window.location = `${window.baseUrl}/sessions/logout`; - }, - - render() { - const isUserAuthenticated = !!window.SS.user; - return isUserAuthenticated ? this.renderAuthenticated() : this.renderAnonymous(); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/global/global-nav.js b/server/sonar-web/src/main/js/main/nav/global/global-nav.js deleted file mode 100644 index 1c2916c56de..00000000000 --- a/server/sonar-web/src/main/js/main/nav/global/global-nav.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import GlobalNavBranding from './global-nav-branding'; -import GlobalNavMenu from './global-nav-menu'; -import GlobalNavUser from './global-nav-user'; -import GlobalNavSearch from './global-nav-search'; -import ShortcutsHelpView from './shortcuts-help-view'; - -export default React.createClass({ - componentDidMount() { - window.addEventListener('keypress', this.onKeyPress); - }, - - componentWillUnmount() { - window.removeEventListener('keypress', this.onKeyPress); - }, - - onKeyPress(e) { - const tagName = e.target.tagName; - const code = e.keyCode || e.which; - const isInput = tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA'; - const isTriggerKey = code === 63; - const isModalOpen = document.querySelector('html').classList.contains('modal-open'); - if (!isInput && !isModalOpen && isTriggerKey) { - this.openHelp(); - } - }, - - openHelp(e) { - if (e) { - e.preventDefault(); - } - new ShortcutsHelpView().render(); - }, - - render() { - return ( -
        - - - - - -
        - ); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/global/search-view.js b/server/sonar-web/src/main/js/main/nav/global/search-view.js deleted file mode 100644 index 98b0c7cb3c8..00000000000 --- a/server/sonar-web/src/main/js/main/nav/global/search-view.js +++ /dev/null @@ -1,264 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 $ from 'jquery'; -import _ from 'underscore'; -import Backbone from 'backbone'; -import Marionette from 'backbone.marionette'; -import SelectableCollectionView from '../../../components/common/selectable-collection-view'; -import SearchItemTemplate from '../templates/nav-search-item.hbs'; -import EmptySearchTemplate from '../templates/nav-search-empty.hbs'; -import SearchTemplate from '../templates/nav-search.hbs'; -import RecentHistory from '../component/RecentHistory'; -import { translate } from '../../../helpers/l10n'; -import { collapsedDirFromPath, fileFromPath } from '../../../helpers/path'; - -const SearchItemView = Marionette.ItemView.extend({ - tagName: 'li', - template: SearchItemTemplate, - - select () { - this.$el.addClass('active'); - }, - - deselect () { - this.$el.removeClass('active'); - }, - - submit () { - this.$('a')[0].click(); - }, - - onRender () { - this.$('[data-toggle="tooltip"]').tooltip({ - container: 'body', - html: true, - placement: 'left', - delay: { show: 500, hide: 0 } - }); - }, - - onDestroy () { - this.$('[data-toggle="tooltip"]').tooltip('destroy'); - }, - - serializeData () { - return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), { - index: this.options.index - }); - } -}); - -const SearchEmptyView = Marionette.ItemView.extend({ - tagName: 'li', - template: EmptySearchTemplate -}); - -const SearchResultsView = SelectableCollectionView.extend({ - className: 'menu', - tagName: 'ul', - childView: SearchItemView, - emptyView: SearchEmptyView -}); - -export default Marionette.LayoutView.extend({ - className: 'navbar-search', - tagName: 'form', - template: SearchTemplate, - - regions: { - resultsRegion: '.js-search-results' - }, - - events: { - 'submit': 'onSubmit', - 'keydown .js-search-input': 'onKeyDown', - 'keyup .js-search-input': 'onKeyUp' - }, - - initialize () { - const that = this; - this.results = new Backbone.Collection(); - this.favorite = []; - if (window.SS.user) { - this.fetchFavorite().always(function () { - that.resetResultsToDefault(); - }); - } else { - this.resetResultsToDefault(); - } - this.resultsView = new SearchResultsView({ collection: this.results }); - this.debouncedSearch = _.debounce(this.search, 250); - this._bufferedValue = ''; - }, - - onRender () { - const that = this; - this.resultsRegion.show(this.resultsView); - setTimeout(function () { - that.$('.js-search-input').focus(); - }, 0); - }, - - onKeyDown (e) { - if (e.keyCode === 38) { - this.resultsView.selectPrev(); - return false; - } - if (e.keyCode === 40) { - this.resultsView.selectNext(); - return false; - } - if (e.keyCode === 13) { - this.resultsView.submitCurrent(); - this.destroy(); - return false; - } - if (e.keyCode === 27) { - this.options.hide(); - return false; - } - }, - - onKeyUp () { - const value = this.$('.js-search-input').val(); - if (value === this._bufferedValue) { - return; - } - this._bufferedValue = this.$('.js-search-input').val(); - this.searchRequest = this.debouncedSearch(value); - }, - - onSubmit () { - return false; - }, - - fetchFavorite () { - const that = this; - return $.get(window.baseUrl + '/api/favourites').done(function (r) { - that.favorite = r.map(function (f) { - const isFile = ['FIL', 'UTS'].indexOf(f.qualifier) !== -1; - return { - url: window.baseUrl + '/dashboard/index?id=' + encodeURIComponent(f.key) + window.dashboardParameters(true), - name: isFile ? collapsedDirFromPath(f.lname) + fileFromPath(f.lname) : f.name, - icon: 'favorite' - }; - }); - that.favorite = _.sortBy(that.favorite, 'name'); - }); - }, - - resetResultsToDefault () { - const recentHistory = RecentHistory.get(); - const history = recentHistory.map(function (historyItem, index) { - const url = window.baseUrl + '/dashboard/index?id=' + encodeURIComponent(historyItem.key) + - window.dashboardParameters(true); - return { - url, - name: historyItem.name, - q: historyItem.icon, - extra: index === 0 ? translate('browsed_recently') : null - }; - }); - const favorite = _.first(this.favorite, 6).map(function (f, index) { - return _.extend(f, { extra: index === 0 ? translate('favorite') : null }); - }); - this.results.reset([].concat(history, favorite)); - }, - - search (q) { - if (q.length < 2) { - this.resetResultsToDefault(); - return; - } - const that = this; - const url = window.baseUrl + '/api/components/suggestions'; - const options = { s: q }; - return $.get(url, options).done(function (r) { - // if the input value has changed since we sent the request, - // just ignore the output, because another request already sent - if (q !== that._bufferedValue) { - return; - } - - const collection = []; - r.results.forEach(function (domain) { - domain.items.forEach(function (item, index) { - collection.push(_.extend(item, { - q: domain.q, - extra: index === 0 ? domain.name : null, - url: window.baseUrl + '/dashboard/index?id=' + encodeURIComponent(item.key) + - window.dashboardParameters(true) - })); - }); - }); - that.results.reset([].concat( - that.getNavigationFindings(q), - that.getGlobalDashboardFindings(q), - that.getFavoriteFindings(q), - collection - )); - }); - }, - - getNavigationFindings (q) { - const DEFAULT_ITEMS = [ - { name: translate('issues.page'), url: window.baseUrl + '/issues/search' }, - { name: translate('layout.measures'), url: window.baseUrl + '/measures/search?qualifiers[]=TRK' }, - { name: translate('coding_rules.page'), url: window.baseUrl + '/coding_rules' }, - { name: translate('quality_profiles.page'), url: window.baseUrl + '/profiles' }, - { name: translate('quality_gates.page'), url: window.baseUrl + '/quality_gates' } - ]; - const customItems = []; - if (window.SS.isUserAdmin) { - customItems.push({ name: translate('layout.settings'), url: window.baseUrl + '/settings' }); - } - const findings = [].concat(DEFAULT_ITEMS, customItems).filter(function (f) { - return f.name.match(new RegExp(q, 'i')); - }); - if (findings.length > 0) { - findings[0].extra = translate('navigation'); - } - return _.first(findings, 6); - }, - - getGlobalDashboardFindings (q) { - const dashboards = this.model.get('globalDashboards') || []; - const items = dashboards.map(function (d) { - return { name: d.name, url: window.baseUrl + '/dashboard/index?did=' + encodeURIComponent(d.key) }; - }); - const findings = items.filter(function (f) { - return f.name.match(new RegExp(q, 'i')); - }); - if (findings.length > 0) { - findings[0].extra = translate('dashboard.global_dashboards'); - } - return _.first(findings, 6); - }, - - getFavoriteFindings (q) { - const findings = this.favorite.filter(function (f) { - return f.name.match(new RegExp(q, 'i')); - }); - if (findings.length > 0) { - findings[0].extra = translate('favorite'); - } - return _.first(findings, 6); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/global/shortcuts-help-view.js b/server/sonar-web/src/main/js/main/nav/global/shortcuts-help-view.js deleted file mode 100644 index 7fbdd302469..00000000000 --- a/server/sonar-web/src/main/js/main/nav/global/shortcuts-help-view.js +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 ModalView from '../../../components/common/modals'; -import ShortcutsHelpTemplate from '../templates/nav-shortcuts-help.hbs'; - -export default ModalView.extend({ - className: 'modal modal-large', - template: ShortcutsHelpTemplate -}); - diff --git a/server/sonar-web/src/main/js/main/nav/links-mixin.js b/server/sonar-web/src/main/js/main/nav/links-mixin.js deleted file mode 100644 index 0027e2250df..00000000000 --- a/server/sonar-web/src/main/js/main/nav/links-mixin.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import classNames from 'classnames'; - -export default { - activeLink(url) { - return window.location.pathname.indexOf(window.baseUrl + url) === 0 ? 'active' : null; - }, - - renderLink(url, title, highlightUrl = url) { - const fullUrl = window.baseUrl + url; - const isActive = typeof highlightUrl === 'string' ? - window.location.pathname.indexOf(window.baseUrl + highlightUrl) === 0 : - highlightUrl(fullUrl); - - return ( -
      • - {title} -
      • - ); - } -}; diff --git a/server/sonar-web/src/main/js/main/nav/settings/settings-nav.js b/server/sonar-web/src/main/js/main/nav/settings/settings-nav.js deleted file mode 100644 index 27e029f37df..00000000000 --- a/server/sonar-web/src/main/js/main/nav/settings/settings-nav.js +++ /dev/null @@ -1,133 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 React from 'react'; -import classNames from 'classnames'; -import some from 'lodash/some'; -import LinksMixin from '../links-mixin'; -import { translate } from '../../../helpers/l10n'; - -export default React.createClass({ - mixins: [LinksMixin], - - getDefaultProps() { - return { extensions: [] }; - }, - - isSomethingActive(urls) { - const path = window.location.pathname; - return some(urls, url => path.indexOf(window.baseUrl + url) === 0); - }, - - isSecurityActive() { - const urls = ['/users', '/groups', '/roles/global', '/permission_templates']; - return this.isSomethingActive(urls); - }, - - isProjectsActive() { - const urls = ['/projects_admin', '/background_tasks']; - return this.isSomethingActive(urls); - }, - - isSystemActive() { - const urls = ['/updatecenter', '/system']; - return this.isSomethingActive(urls); - }, - - render() { - const isSecurity = this.isSecurityActive(); - const isProjects = this.isProjectsActive(); - const isSystem = this.isSystemActive(); - - const securityClassName = classNames('dropdown', { active: isSecurity }); - const projectsClassName = classNames('dropdown', { active: isProjects }); - const systemClassName = classNames('dropdown', { active: isSystem }); - const configurationClassNames = classNames('dropdown', { - active: !isSecurity && !isProjects && !isSystem - }); - - return ( -
        -
          - {this.renderLink('/settings', translate('layout.settings'))} -
        - -
          -
        • - - {translate('sidebar.project_settings')} - {' '} - - -
            - {this.renderLink('/settings', translate('settings.page'), url => window.location.pathname === url)} - {this.renderLink('/settings/licenses', translate('property.category.licenses'))} - {this.renderLink('/settings/encryption', translate('property.category.security.encryption'))} - {this.renderLink('/settings/server_id', translate('property.category.server_id'))} - {this.renderLink('/metrics', 'Custom Metrics')} - {this.props.extensions.map(e => this.renderLink(e.url, e.name))} -
          -
        • - -
        • - - {translate('sidebar.security')} - {' '} - - -
            - {this.renderLink('/users', translate('users.page'))} - {this.renderLink('/groups', translate('user_groups.page'))} - {this.renderLink('/roles/global', - translate('global_permissions.page'))} - {this.renderLink('/permission_templates', - translate('permission_templates'))} -
          -
        • - -
        • - - {translate('sidebar.projects')} - {' '} - - -
            - {this.renderLink('/projects_admin', 'Management')} - {this.renderLink('/background_tasks', - translate('background_tasks.page'))} -
          -
        • - -
        • - - {translate('sidebar.system')} - {' '} - - -
            - {this.renderLink('/updatecenter', translate('update_center.page'))} - {this.renderLink('/system', translate('system_info.page'))} -
          -
        • -
        -
        - - ); - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/templates/nav-search-empty.hbs b/server/sonar-web/src/main/js/main/nav/templates/nav-search-empty.hbs deleted file mode 100644 index fb76e686612..00000000000 --- a/server/sonar-web/src/main/js/main/nav/templates/nav-search-empty.hbs +++ /dev/null @@ -1 +0,0 @@ -{{t 'no_results'}} diff --git a/server/sonar-web/src/main/js/main/nav/templates/nav-search-item.hbs b/server/sonar-web/src/main/js/main/nav/templates/nav-search-item.hbs deleted file mode 100644 index 25128ddfc20..00000000000 --- a/server/sonar-web/src/main/js/main/nav/templates/nav-search-item.hbs +++ /dev/null @@ -1,22 +0,0 @@ -{{#notNull extra}} - {{#gt index 0}} -
        - {{/gt}} - {{#if extra}} - - {{/if}} -{{/notNull}} - - - {{#if icon}}{{/if}} - {{#if q}}{{qualifierIcon q}}{{/if}} - {{#eq q 'FIL'}} - {{collapsedDirFromPath name}}{{fileFromPath name}} - {{else}} - {{#eq q 'UTS'}} - {{collapsedDirFromPath name}}{{fileFromPath name}} - {{else}} - {{name}} - {{/eq}} - {{/eq}} - diff --git a/server/sonar-web/src/main/js/main/nav/templates/nav-search.hbs b/server/sonar-web/src/main/js/main/nav/templates/nav-search.hbs deleted file mode 100644 index 68e1f3ad168..00000000000 --- a/server/sonar-web/src/main/js/main/nav/templates/nav-search.hbs +++ /dev/null @@ -1,8 +0,0 @@ - - - - -
        - - diff --git a/server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs b/server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs deleted file mode 100644 index ae4f9967233..00000000000 --- a/server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs +++ /dev/null @@ -1,61 +0,0 @@ - - - - - diff --git a/server/sonar-web/src/main/js/main/processes.js b/server/sonar-web/src/main/js/main/processes.js deleted file mode 100644 index 4519004243b..00000000000 --- a/server/sonar-web/src/main/js/main/processes.js +++ /dev/null @@ -1,190 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 $ from 'jquery'; -import _ from 'underscore'; -import Backbone from 'backbone'; -import Marionette from 'backbone.marionette'; -import escapeHtml from 'escape-html'; -import { translate } from '../helpers/l10n'; -import { getCSRFTokenName, getCSRFTokenValue } from '../helpers/request'; - -const defaults = { - queue: {}, - timeout: 300, - fadeTimeout: 100 -}; - -const Process = Backbone.Model.extend({ - defaults: { - state: 'ok' - }, - - timeout () { - this.set({ - state: 'timeout', - message: 'Still Working...' - }); - }, - - finish (options) { - options = _.defaults(options || {}, { force: false }); - if (this.get('state') !== 'failed' || !!options.force) { - this.trigger('destroy', this, this.collection, options); - } - }, - - fail (message) { - const that = this; - let msg = message || translate('process.fail'); - if (msg === 'process.fail') { - // no translation - msg = 'An error happened, some parts of the page might not render correctly. ' + - 'Please contact the administrator if you keep on experiencing this error.'; - } - clearInterval(this.get('timer')); - this.set({ - state: 'failed', - message: msg - }); - this.set('state', 'failed'); - setTimeout(function () { - that.finish({ force: true }); - }, 5000); - } -}); - -const Processes = Backbone.Collection.extend({ - model: Process -}); - -const ProcessesView = Marionette.ItemView.extend({ - tagName: 'ul', - className: 'processes-container', - - collectionEvents: { - 'all': 'render' - }, - - render () { - const failed = this.collection.findWhere({ state: 'failed' }); - const timeout = this.collection.findWhere({ state: 'timeout' }); - let el; - this.$el.empty(); - if (failed != null) { - el = $('
      • ') - .html(failed.get('message')) - .addClass('process-spinner process-spinner-failed shown'); - const close = $('').html('').addClass('process-spinner-close'); - close.appendTo(el); - close.on('click', function () { - failed.finish({ force: true }); - }); - el.appendTo(this.$el); - } else if (timeout != null) { - el = $('
      • ') - .html(timeout.get('message')) - .addClass('process-spinner shown'); - el.appendTo(this.$el); - } - return this; - } -}); - -const processes = new Processes(); -const processesView = new ProcessesView({ - collection: processes -}); - -/** - * Add background process - * @returns {number} - */ -function addBackgroundProcess () { - const uid = _.uniqueId('process'); - const process = new Process({ - id: uid, - timer: setTimeout(function () { - process.timeout(); - }, defaults.timeout) - }); - processes.add(process); - return uid; -} - -/** - * Finish background process - * @param {number} uid - */ -function finishBackgroundProcess (uid) { - const process = processes.get(uid); - if (process != null) { - process.finish(); - } -} - -/** - * Fail background process - * @param {number} uid - * @param {string} message - */ -function failBackgroundProcess (uid, message) { - const process = processes.get(uid); - if (process != null) { - process.fail(message); - } -} - -/** - * Handle ajax error - * @param jqXHR - */ -function handleAjaxError (jqXHR) { - if (jqXHR != null && jqXHR.processId != null) { - let message = null; - if (jqXHR.responseJSON != null && jqXHR.responseJSON.errors != null) { - message = _.pluck(jqXHR.responseJSON.errors, 'msg').join('. '); - } - failBackgroundProcess(jqXHR.processId, message ? escapeHtml(message) : null); - } -} - -$.ajaxSetup({ - beforeSend (jqXHR) { - jqXHR.setRequestHeader(getCSRFTokenName(), getCSRFTokenValue()); - jqXHR.processId = addBackgroundProcess(); - }, - complete (jqXHR) { - if (jqXHR.processId != null) { - finishBackgroundProcess(jqXHR.processId); - } - }, - statusCode: { - 400: handleAjaxError, - 403: handleAjaxError, - 500: handleAjaxError, - 502: handleAjaxError, - 503: handleAjaxError, - 504: handleAjaxError - } -}); - -$(function () { - processesView.render().$el.insertBefore('#footer'); -}); diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/about/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/about/index.html.erb index fcb9a089ebf..7b618242ab9 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/about/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/about/index.html.erb @@ -15,5 +15,4 @@ <% end %> ]; - <% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/account/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/account/index.html.erb index 2a9a0762193..c15f578952f 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/account/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/account/index.html.erb @@ -72,5 +72,4 @@ ] }; - <% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/background_tasks/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/background_tasks/index.html.erb index 18cce998a6f..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/background_tasks/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/background_tasks/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/code/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/code/index.html.erb index f5600f6ca03..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/code/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/code/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb index 7d421c9d66d..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_issues/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_issues/index.html.erb index b2b853e610b..6989a49b051 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_issues/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_issues/index.html.erb @@ -9,5 +9,4 @@ }; })(); - <% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_measures/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_measures/index.html.erb index 96d117fa27e..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_measures/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_measures/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/custom_measures/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/custom_measures/index.html.erb index 8a7e139e257..6e435e85c27 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/custom_measures/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/custom_measures/index.html.erb @@ -2,5 +2,4 @@ - <% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/dashboard/overview.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/dashboard/overview.html.erb index aecf8510253..5ca6b6fba86 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/dashboard/overview.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/dashboard/overview.html.erb @@ -80,5 +80,4 @@ }; })(); - <% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/index.html.erb index e3bee63260c..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/issues/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/issues/index.html.erb index b1baf27f96c..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/issues/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/issues/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_footer.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_footer.html.erb index 71f1c60dedb..e4ff4db0048 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_footer.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_footer.html.erb @@ -24,7 +24,7 @@ <% end %> <% cookies.delete 'flash' %> - + <%= yield :extra_script -%> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/nonav.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/nonav.html.erb index be802926bd3..8eddafc65d3 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/nonav.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/nonav.html.erb @@ -36,7 +36,7 @@ })(window.jQuery); - + <%= yield :extra_script -%> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/maintenance/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/maintenance/index.html.erb index 346aa13f860..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/maintenance/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/maintenance/index.html.erb @@ -1,7 +0,0 @@ -<% content_for :extra_script do %> - - -<% end %> - diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/markdown/help.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/markdown/help.html.erb index 6f667bc45cd..ff4b4bc60ae 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/markdown/help.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/markdown/help.html.erb @@ -1,8 +1,102 @@ -
        - -<% content_for :extra_script do %> - - -<% end %> +
        +

        Markdown Syntax

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Write:To display:
        *this text is bold*this text is bold
        http://sonarqube.orghttp://sonarqube.org
        + [SonarQube™ Home Page](http://www.sonarqube.org) + + SonarQube™ Home Page +
        * first item
        + * second item +
        +
          +
        • first item
        • +
        • second item
        • +
        +
        1. first item
        + 1. second item +
        +
          +
        1. first item
        2. +
        3. second item
        4. +
        +
        + = Heading Level 1
        + == Heading Level 2
        + === Heading Level 3
        + ==== Heading Level 4
        + ===== Heading Level 5
        + ====== Heading Level 6
        +
        +

        Heading Level 1

        +

        Heading Level 2

        +

        Heading Level 3

        +

        Heading Level 4

        +
        Heading Level 5
        +
        Heading Level 6
        +
        ``Lists#newArrayList()``Lists#newArrayList()
        + ``
        + // code on multiple lines
        + public void foo() {
        +   // do some logic here
        + }
        + `` +
        +
        +  // code on multiple lines
        +  public void foo() {
        +  // do some logic here
        +  }
        +
        +
        + Standard text
        + > Blockquoted text
        + > that spans multiple lines
        +
        +

        Standard text

        +
        Blockquoted text
        + that spans multiple lines
        +
        +
        diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/metrics/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/metrics/index.html.erb index 5a8e0641d97..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/metrics/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/metrics/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/permission_templates/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/permission_templates/index.html.erb index fb97f387c59..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/permission_templates/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/permission_templates/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb index 513b41c5692..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/background_tasks.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/background_tasks.html.erb index ba6d27a4da6..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/background_tasks.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/background_tasks.html.erb @@ -1,6 +0,0 @@ -<% content_for :extra_script do %> - - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/deletion.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/deletion.html.erb index e9dd9ae3410..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/deletion.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/deletion.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/key.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/key.html.erb index e9dd9ae3410..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/key.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/key.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/links.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/links.html.erb index e9dd9ae3410..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/links.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/links.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/quality_gate.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/quality_gate.html.erb index e9dd9ae3410..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/quality_gate.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/quality_gate.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/quality_profiles.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/quality_profiles.html.erb index e9dd9ae3410..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/quality_profiles.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/quality_profiles.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/settings.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/settings.html.erb index c0f9f94d9f0..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/settings.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project/settings.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project_roles/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project_roles/index.html.erb index df0126ffd09..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project_roles/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project_roles/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects/index.html.erb index 513b41c5692..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects_admin/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects_admin/index.html.erb index 3c6e21dbbd1..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects_admin/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects_admin/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb index 513b41c5692..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/roles/global.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/roles/global.html.erb index 3c79bb2feca..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/roles/global.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/roles/global.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/settings/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/settings/index.html.erb index 6c42ad1d4b7..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/settings/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/settings/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/setup/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/setup/index.html.erb index a06263ce445..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/setup/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/setup/index.html.erb @@ -1,7 +0,0 @@ -<% content_for :extra_script do %> - - -<% end %> - diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/system/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/system/index.html.erb index 1cb19867388..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/system/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/system/index.html.erb @@ -1,4 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> - diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/updatecenter/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/updatecenter/index.html.erb index 403d4baf226..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/updatecenter/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/updatecenter/index.html.erb @@ -1,7 +0,0 @@ -<% content_for :extra_script do %> - - -<% end %> - diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/index.html.erb index 56d012090af..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/index.html.erb @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/web_api/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/web_api/index.html.erb index 8edb6222ec3..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/web_api/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/web_api/index.html.erb @@ -1,6 +0,0 @@ -<% content_for :extra_script do %> - - -<% end %> -- cgit v1.2.3