瀏覽代碼

comment flow annotations (#2335)

tags/6.6-RC1
Stas Vilchik 6 年之前
父節點
當前提交
90306cb436
共有 100 個檔案被更改,包括 816 行新增535 行删除
  1. 1
    1
      server/sonar-web/.eslintrc
  2. 1
    1
      server/sonar-web/package.json
  3. 7
    2
      server/sonar-web/src/main/js/api/application.js
  4. 29
    15
      server/sonar-web/src/main/js/api/ce.js
  5. 67
    46
      server/sonar-web/src/main/js/api/components.js
  6. 5
    3
      server/sonar-web/src/main/js/api/favorites.js
  7. 50
    25
      server/sonar-web/src/main/js/api/issues.js
  8. 19
    8
      server/sonar-web/src/main/js/api/notifications.js
  9. 43
    23
      server/sonar-web/src/main/js/api/organizations.js
  10. 80
    67
      server/sonar-web/src/main/js/api/permissions.js
  11. 32
    23
      server/sonar-web/src/main/js/api/projectActivity.js
  12. 15
    15
      server/sonar-web/src/main/js/api/quality-profiles.js
  13. 17
    13
      server/sonar-web/src/main/js/api/time-machine.js
  14. 7
    7
      server/sonar-web/src/main/js/api/user-tokens.js
  15. 12
    6
      server/sonar-web/src/main/js/api/user_groups.js
  16. 14
    7
      server/sonar-web/src/main/js/api/users.js
  17. 11
    2
      server/sonar-web/src/main/js/api/web-api.js
  18. 1
    1
      server/sonar-web/src/main/js/app/components/App.js
  19. 1
    1
      server/sonar-web/src/main/js/app/components/GlobalContainer.js
  20. 5
    6
      server/sonar-web/src/main/js/app/components/GlobalFooter.js
  21. 1
    1
      server/sonar-web/src/main/js/app/components/LocalizationContainer.js
  22. 2
    0
      server/sonar-web/src/main/js/app/components/MigrationContainer.js
  23. 2
    0
      server/sonar-web/src/main/js/app/components/ProjectAdminContainer.js
  24. 3
    1
      server/sonar-web/src/main/js/app/components/ProjectContainer.js
  25. 11
    9
      server/sonar-web/src/main/js/app/components/RecentHistory.js
  26. 3
    1
      server/sonar-web/src/main/js/app/components/SimpleContainer.js
  27. 7
    5
      server/sonar-web/src/main/js/app/components/extensions/Extension.js
  28. 3
    1
      server/sonar-web/src/main/js/app/components/extensions/GlobalAdminPageExtension.js
  29. 3
    1
      server/sonar-web/src/main/js/app/components/extensions/GlobalPageExtension.js
  30. 5
    3
      server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.js
  31. 1
    1
      server/sonar-web/src/main/js/app/components/extensions/PortfoliosPage.js
  32. 4
    2
      server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.js
  33. 4
    2
      server/sonar-web/src/main/js/app/components/extensions/ProjectPageExtension.js
  34. 1
    1
      server/sonar-web/src/main/js/app/components/extensions/ViewDashboard.js
  35. 5
    4
      server/sonar-web/src/main/js/app/components/extensions/utils.js
  36. 9
    5
      server/sonar-web/src/main/js/app/components/help/GlobalHelp.js
  37. 3
    1
      server/sonar-web/src/main/js/app/components/help/LinksHelp.js
  38. 3
    1
      server/sonar-web/src/main/js/app/components/help/LinksHelpSonarCloud.js
  39. 4
    2
      server/sonar-web/src/main/js/app/components/help/TutorialsHelp.js
  40. 1
    1
      server/sonar-web/src/main/js/app/components/help/__tests__/GlobalHelp-test.js
  41. 7
    3
      server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js
  42. 13
    7
      server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js
  43. 27
    22
      server/sonar-web/src/main/js/app/components/search/Search.js
  44. 11
    7
      server/sonar-web/src/main/js/app/components/search/SearchResult.js
  45. 4
    2
      server/sonar-web/src/main/js/app/components/search/SearchResults.js
  46. 5
    3
      server/sonar-web/src/main/js/app/components/search/SearchShowMore.js
  47. 6
    6
      server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.js
  48. 1
    1
      server/sonar-web/src/main/js/app/components/search/__tests__/SearchResult-test.js
  49. 1
    1
      server/sonar-web/src/main/js/app/components/search/__tests__/SearchResults-test.js
  50. 7
    1
      server/sonar-web/src/main/js/app/components/search/utils.js
  51. 2
    2
      server/sonar-web/src/main/js/app/utils/installExtensionsHandler.js
  52. 1
    1
      server/sonar-web/src/main/js/app/utils/throwGlobalError.js
  53. 1
    2
      server/sonar-web/src/main/js/apps/about/actions.js
  54. 6
    3
      server/sonar-web/src/main/js/apps/about/components/AboutApp.js
  55. 3
    1
      server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js
  56. 3
    1
      server/sonar-web/src/main/js/apps/about/components/AboutProjects.js
  57. 3
    1
      server/sonar-web/src/main/js/apps/about/components/AboutRulesForSonarQubeDotCom.js
  58. 3
    1
      server/sonar-web/src/main/js/apps/about/components/AboutStandards.js
  59. 5
    1
      server/sonar-web/src/main/js/apps/about/components/EntryIssueTypes.js
  60. 5
    6
      server/sonar-web/src/main/js/apps/about/components/EntryIssueTypesForSonarQubeDotCom.js
  61. 5
    3
      server/sonar-web/src/main/js/apps/about/components/SonarCloudGetStarted.js
  62. 3
    1
      server/sonar-web/src/main/js/apps/account/components/Nav.js
  63. 5
    3
      server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js
  64. 2
    1
      server/sonar-web/src/main/js/apps/account/notifications/Notifications.js
  65. 6
    5
      server/sonar-web/src/main/js/apps/account/notifications/NotificationsList.js
  66. 4
    3
      server/sonar-web/src/main/js/apps/account/notifications/ProjectNotifications.js
  67. 7
    3
      server/sonar-web/src/main/js/apps/account/notifications/Projects.js
  68. 6
    6
      server/sonar-web/src/main/js/apps/account/notifications/actions.js
  69. 10
    7
      server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.js
  70. 4
    2
      server/sonar-web/src/main/js/apps/account/organizations/OrganizationCard.js
  71. 4
    2
      server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.js
  72. 5
    4
      server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.js
  73. 2
    5
      server/sonar-web/src/main/js/apps/account/organizations/actions.js
  74. 3
    1
      server/sonar-web/src/main/js/apps/account/profile/Profile.js
  75. 14
    10
      server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
  76. 3
    1
      server/sonar-web/src/main/js/apps/background-tasks/components/CurrentsFilter.js
  77. 2
    2
      server/sonar-web/src/main/js/apps/background-tasks/components/Footer.js
  78. 3
    1
      server/sonar-web/src/main/js/apps/background-tasks/components/Header.js
  79. 8
    4
      server/sonar-web/src/main/js/apps/background-tasks/components/ScannerContext.js
  80. 7
    7
      server/sonar-web/src/main/js/apps/background-tasks/components/Search.js
  81. 8
    4
      server/sonar-web/src/main/js/apps/background-tasks/components/Stacktrace.js
  82. 8
    4
      server/sonar-web/src/main/js/apps/background-tasks/components/Stats.js
  83. 1
    1
      server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.js
  84. 4
    2
      server/sonar-web/src/main/js/apps/background-tasks/components/TaskComponent.js
  85. 4
    6
      server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.js
  86. 2
    2
      server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.js
  87. 2
    2
      server/sonar-web/src/main/js/apps/background-tasks/components/TaskExecutionTime.js
  88. 2
    2
      server/sonar-web/src/main/js/apps/background-tasks/components/TaskStatus.js
  89. 2
    2
      server/sonar-web/src/main/js/apps/background-tasks/components/TaskType.js
  90. 6
    2
      server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js
  91. 4
    6
      server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.js
  92. 11
    7
      server/sonar-web/src/main/js/apps/background-tasks/components/Workers.js
  93. 13
    7
      server/sonar-web/src/main/js/apps/background-tasks/components/WorkersForm.js
  94. 2
    0
      server/sonar-web/src/main/js/apps/background-tasks/types.js
  95. 4
    4
      server/sonar-web/src/main/js/apps/background-tasks/utils.js
  96. 3
    2
      server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js
  97. 9
    3
      server/sonar-web/src/main/js/apps/coding-rules/init.js
  98. 15
    15
      server/sonar-web/src/main/js/apps/component-measures/components/App.js
  99. 7
    7
      server/sonar-web/src/main/js/apps/component-measures/components/AppContainer.js
  100. 0
    0
      server/sonar-web/src/main/js/apps/component-measures/components/Breadcrumb.js

+ 1
- 1
server/sonar-web/.eslintrc 查看文件

@@ -27,7 +27,7 @@
"rules": {
"array-bracket-spacing": 2,
"array-callback-return": 2,
"arrow-parens": [2, "as-needed"],
// "arrow-parens": [2, "as-needed"],
"arrow-spacing": 2,
"block-scoped-var": 2,
"block-spacing": 2,

+ 1
- 1
server/sonar-web/package.json 查看文件

@@ -68,7 +68,7 @@
"eslint-plugin-react": "^6.8.0",
"expose-loader": "0.7.3",
"extract-text-webpack-plugin": "2.1.2",
"flow-bin": "0.47.0",
"flow-bin": "^0.52.0",
"fs-extra": "0.30.0",
"handlebars-loader": "1.5.0",
"html-webpack-plugin": "2.28.0",

+ 7
- 2
server/sonar-web/src/main/js/api/application.js 查看文件

@@ -21,11 +21,16 @@
import { getJSON } from '../helpers/request';
import throwGlobalError from '../app/utils/throwGlobalError';

/*::
type GetApplicationLeakResponse = Array<{
date: string,
project: string,
projectName: string
}>;
*/

export const getApplicationLeak = (application: string): Promise<GetApplicationLeakResponse> =>
getJSON('/api/views/show_leak', { application }).then(r => r.leaks, throwGlobalError);
export function getApplicationLeak(
application /*: string */
) /*: Promise<GetApplicationLeakResponse> */ {
return getJSON('/api/views/show_leak', { application }).then(r => r.leaks, throwGlobalError);
}

+ 29
- 15
server/sonar-web/src/main/js/api/ce.js 查看文件

@@ -21,31 +21,45 @@
import { getJSON, post } from '../helpers/request';
import throwGlobalError from '../app/utils/throwGlobalError';

export const getActivity = (data?: Object): Promise<*> => getJSON('/api/ce/activity', data);
export function getActivity(data /*: ?Object */) /*: Promise<*> */ {
return getJSON('/api/ce/activity', data);
}

export const getStatus = (componentId?: string): Promise<*> => {
export function getStatus(componentId /*: ?string */) /*: Promise<*> */ {
const data = {};
if (componentId) {
Object.assign(data, { componentId });
}
return getJSON('/api/ce/activity_status', data);
};
}

export const getTask = (id: string, additionalFields?: Array<string>): Promise<*> =>
getJSON('/api/ce/task', { id, additionalFields }).then(r => r.task);
export function getTask(
id /*: string */,
additionalFields /*: ?Array<string> */
) /*: Promise<*> */ {
return getJSON('/api/ce/task', { id, additionalFields }).then(r => r.task);
}

export const cancelTask = (id: string): Promise<*> =>
post('/api/ce/cancel', { id }).then(() => getTask(id), () => getTask(id));
export function cancelTask(id /*: string */) /*: Promise<*> */ {
return post('/api/ce/cancel', { id }).then(() => getTask(id), () => getTask(id));
}

export const cancelAllTasks = (): Promise<*> => post('/api/ce/cancel_all');
export function cancelAllTasks() /*: Promise<*> */ {
return post('/api/ce/cancel_all');
}

export const getTasksForComponent = (componentKey: string): Promise<*> =>
getJSON('/api/ce/component', { componentKey });
export function getTasksForComponent(componentKey /*: string */) /*: Promise<*> */ {
return getJSON('/api/ce/component', { componentKey });
}

export const getTypes = (): Promise<*> => getJSON('/api/ce/task_types').then(r => r.taskTypes);
export function getTypes() /*: Promise<*> */ {
return getJSON('/api/ce/task_types').then(r => r.taskTypes);
}

export const getWorkers = (): Promise<{ canSetWorkerCount: boolean, value: number }> =>
getJSON('/api/ce/worker_count').catch(throwGlobalError);
export function getWorkers() /*: Promise<{ canSetWorkerCount: boolean, value: number }> */ {
return getJSON('/api/ce/worker_count').catch(throwGlobalError);
}

export const setWorkerCount = (count: number): Promise<void> =>
post('/api/ce/set_worker_count', { count }).catch(throwGlobalError);
export function setWorkerCount(count /*: number */) /*: Promise<void> */ {
return post('/api/ce/set_worker_count', { count }).catch(throwGlobalError);
}

+ 67
- 46
server/sonar-web/src/main/js/api/components.js 查看文件

@@ -21,57 +21,59 @@
import { getJSON, postJSON, post } from '../helpers/request';
import throwGlobalError from '../app/utils/throwGlobalError';

export function getComponents(data?: Object) {
export function getComponents(data /*: ?Object */) {
const url = '/api/projects/search';
return getJSON(url, data);
}

export function getProvisioned(data?: Object) {
export function getProvisioned(data /*: ?Object */) {
const url = '/api/projects/provisioned';
return getJSON(url, data);
}

export function getGhosts(data?: Object) {
export function getGhosts(data /*: ?Object */) {
const url = '/api/projects/ghosts';
return getJSON(url, data);
}

export function deleteComponents(data: { projects: string, organization?: string }) {
export function deleteComponents(data /*: { projects: string, organization?: string } */) {
const url = '/api/projects/bulk_delete';
return post(url, data);
}

export function deleteProject(project: string) {
export function deleteProject(project /*: string */) {
const url = '/api/projects/delete';
const data = { project };
return post(url, data);
}

export function createProject(data: {
export function createProject(
data /*: {
branch?: string,
name: string,
project: string,
organization?: string
}) {
} */
) {
const url = '/api/projects/create';
return postJSON(url, data).catch(throwGlobalError);
}

export function searchProjectTags(data?: { ps?: number, q?: string }) {
export function searchProjectTags(data /*: ?{ ps?: number, q?: string } */) {
const url = '/api/project_tags/search';
return getJSON(url, data);
}

export function setProjectTags(data: { project: string, tags: string }) {
export function setProjectTags(data /*: { project: string, tags: string } */) {
const url = '/api/project_tags/set';
return post(url, data);
}

export function getComponentTree(
strategy: string,
componentKey: string,
metrics: Array<string> = [],
additional?: Object = {}
strategy /*: string */,
componentKey /*: string */,
metrics /*: Array<string> */ = [],
additional /*: ?Object */ = {}
) {
const url = '/api/measures/component_tree';
const data = Object.assign({}, additional, {
@@ -82,62 +84,67 @@ export function getComponentTree(
return getJSON(url, data);
}

export function getChildren(componentKey: string, metrics?: Array<string>, additional?: Object) {
export function getChildren(
componentKey /*: string */,
metrics /*: Array<string> | void */,
additional /*: ?Object */
) {
return getComponentTree('children', componentKey, metrics, additional);
}

export function getComponentLeaves(
componentKey: string,
metrics?: Array<string>,
additional?: Object
componentKey /*: string */,
metrics /*: Array<string> | void */,
additional /*: ?Object */
) {
return getComponentTree('leaves', componentKey, metrics, additional);
}

export function getComponent(componentKey: string, metrics: Array<string> = []) {
export function getComponent(componentKey /*: string */, metrics /*: Array<string> */ = []) {
const url = '/api/measures/component';
const data = { componentKey, metricKeys: metrics.join(',') };
return getJSON(url, data).then(r => r.component);
}

export function getTree(component: string, options?: Object = {}) {
export function getTree(component /*: string */, options /*: ?Object */ = {}) {
const url = '/api/components/tree';
const data = { ...options, component };
return getJSON(url, data);
}

export function getComponentShow(component: string) {
export function getComponentShow(component /*: string */) {
const url = '/api/components/show';
return getJSON(url, { component });
}

export function getParents(component: string) {
export function getParents(component /*: string */) {
return getComponentShow(component).then(r => r.ancestors);
}

export function getBreadcrumbs(component: string) {
export function getBreadcrumbs(component /*: string */) {
return getComponentShow(component).then(r => {
const reversedAncestors = [...r.ancestors].reverse();
return [...reversedAncestors, r.component];
});
}

export function getComponentData(component: string) {
export function getComponentData(component /*: string */) {
return getComponentShow(component).then(r => r.component);
}

export function getMyProjects(data?: Object) {
export function getMyProjects(data /*: ?Object */) {
const url = '/api/projects/search_my_projects';
return getJSON(url, data);
}

export function searchProjects(data?: Object) {
export function searchProjects(data /*: ?Object */) {
const url = '/api/components/search_projects';
return getJSON(url, data);
}

export const searchComponents = (data?: { q?: string, qualifiers?: string, ps?: number }) =>
getJSON('/api/components/search', data);
export function searchComponents(data /*: ?{ q?: string, qualifiers?: string, ps?: number } */) {
return getJSON('/api/components/search', data);
}

/**
* Change component's key
@@ -145,7 +152,7 @@ export const searchComponents = (data?: { q?: string, qualifiers?: string, ps?:
* @param {string} to
* @returns {Promise}
*/
export function changeKey(from: string, to: string) {
export function changeKey(from /*: string */, to /*: string */) {
const url = '/api/projects/update_key';
const data = { from, to };
return post(url, data);
@@ -159,12 +166,18 @@ export function changeKey(from: string, to: string) {
* @param {boolean} dryRun
* @returns {Promise}
*/
export function bulkChangeKey(project: string, from: string, to: string, dryRun?: boolean = false) {
export function bulkChangeKey(
project /*: string */,
from /*: string */,
to /*: string */,
dryRun /*: ?boolean */ = false
) {
const url = '/api/projects/bulk_update_key';
const data = { project, from, to, dryRun };
return postJSON(url, data);
}

/*::
export type SuggestionsResponse = {
organizations: Array<{
key: string,
@@ -189,13 +202,14 @@ export type SuggestionsResponse = {
}>,
warning?: string
};

export const getSuggestions = (
query?: string,
recentlyBrowsed?: Array<string>,
more?: string
): Promise<SuggestionsResponse> => {
const data: Object = {};
*/

export function getSuggestions(
query /*: ?string */,
recentlyBrowsed /*: ?Array<string> */,
more /*: ?string */
) /*: Promise<SuggestionsResponse> */ {
const data /*: Object */ = {};
if (query) {
data.s = query;
}
@@ -206,13 +220,18 @@ export const getSuggestions = (
data.more = more;
}
return getJSON('/api/components/suggestions', data);
};
}

export const getComponentForSourceViewer = (component: string): Promise<*> =>
getJSON('/api/components/app', { component });
export function getComponentForSourceViewer(component /*: string */) /*: Promise<*> */ {
return getJSON('/api/components/app', { component });
}

export const getSources = (component: string, from?: number, to?: number): Promise<Array<*>> => {
const data: Object = { key: component };
export function getSources(
component /*: string */,
from /*: ?number */,
to /*: ?number */
) /*: Promise<Array<*>> */ {
const data /*: Object */ = { key: component };
if (from) {
Object.assign(data, { from });
}
@@ -220,12 +239,14 @@ export const getSources = (component: string, from?: number, to?: number): Promi
Object.assign(data, { to });
}
return getJSON('/api/sources/lines', data).then(r => r.sources);
};
}

export const getDuplications = (component: string): Promise<*> =>
getJSON('/api/duplications/show', { key: component });
export function getDuplications(component /*: string */) /*: Promise<*> */ {
return getJSON('/api/duplications/show', { key: component });
}

export const getTests = (component: string, line: number | string): Promise<*> =>
getJSON('/api/tests/list', { sourceFileKey: component, sourceFileLineNumber: line }).then(
export function getTests(component /*: string */, line /*: number | string */) /*: Promise<*> */ {
return getJSON('/api/tests/list', { sourceFileKey: component, sourceFileLineNumber: line }).then(
r => r.tests
);
}

+ 5
- 3
server/sonar-web/src/main/js/api/favorites.js 查看文件

@@ -20,12 +20,14 @@
/* @flow */
import { post, getJSON } from '../helpers/request';

export const getFavorites = (): Promise<Object> => getJSON('/api/favorites/search');
export function getFavorites() /*: Promise<Object> */ {
return getJSON('/api/favorites/search');
}

export function addFavorite(component: string) {
export function addFavorite(component /*: string */) {
return post('/api/favorites/add', { component });
}

export function removeFavorite(component: string) {
export function removeFavorite(component /*: string */) {
return post('/api/favorites/remove', { component });
}

+ 50
- 25
server/sonar-web/src/main/js/api/issues.js 查看文件

@@ -20,13 +20,16 @@
// @flow
import { getJSON, post, postJSON } from '../helpers/request';

/*::
export type IssueResponse = {
components?: Array<*>,
issue: {},
rules?: Array<*>,
users?: Array<*>
};
*/

/*::
type IssuesResponse = {
components?: Array<*>,
debtTotal?: number,
@@ -40,11 +43,13 @@ type IssuesResponse = {
rules?: Array<*>,
users?: Array<*>
};
*/

export const searchIssues = (query: {}): Promise<IssuesResponse> =>
getJSON('/api/issues/search', query);
export function searchIssues(query /*: {} */) /*: Promise<IssuesResponse> */ {
return getJSON('/api/issues/search', query);
}

export function getFacets(query: {}, facets: Array<string>): Promise<*> {
export function getFacets(query /*: {} */, facets /*: Array<string> */) /*: Promise<*> */ {
const data = {
...query,
facets: facets.join(),
@@ -56,43 +61,48 @@ export function getFacets(query: {}, facets: Array<string>): Promise<*> {
});
}

export function getFacet(query: {}, facet: string): Promise<*> {
export function getFacet(query /*: {} */, facet /*: string */) /*: Promise<*> */ {
return getFacets(query, [facet]).then(r => {
return { facet: r.facets[0].values, response: r.response };
});
}

export function getSeverities(query: {}): Promise<*> {
export function getSeverities(query /*: {} */) /*: Promise<*> */ {
return getFacet(query, 'severities').then(r => r.facet);
}

export function getTags(query: {}): Promise<*> {
export function getTags(query /*: {} */) /*: Promise<*> */ {
return getFacet(query, 'tags').then(r => r.facet);
}

export function extractAssignees(facet: Array<{ val: string }>, response: IssuesResponse) {
export function extractAssignees(
facet /*: Array<{ val: string }> */,
response /*: IssuesResponse */
) {
return facet.map(item => {
const user = response.users ? response.users.find(user => user.login === item.val) : null;
return { ...item, user };
});
}

export function getAssignees(query: {}): Promise<*> {
export function getAssignees(query /*: {} */) /*: Promise<*> */ {
return getFacet(query, 'assignees').then(r => extractAssignees(r.facet, r.response));
}

export function getIssuesCount(query: {}): Promise<*> {
export function getIssuesCount(query /*: {} */) /*: Promise<*> */ {
const data = { ...query, ps: 1, facetMode: 'effort' };
return searchIssues(data).then(r => {
return { issues: r.paging.total, debt: r.debtTotal };
});
}

export const searchIssueTags = (
data: { organization?: string, ps?: number, q?: string } = { ps: 500 }
): Promise<Array<string>> => getJSON('/api/issues/tags', data).then(r => r.tags);
export function searchIssueTags(
data /*: { organization?: string, ps?: number, q?: string } */ = { ps: 500 }
) /*: Promise<Array<string>> */ {
return getJSON('/api/issues/tags', data).then(r => r.tags);
}

export function getIssueChangelog(issue: string): Promise<*> {
export function getIssueChangelog(issue /*: string */) /*: Promise<*> */ {
const url = '/api/issues/changelog';
return getJSON(url, { issue }).then(r => r.changelog);
}
@@ -102,54 +112,69 @@ export function getIssueFilters() {
return getJSON(url).then(r => r.issueFilters);
}

export function addIssueComment(data: { issue: string, text: string }): Promise<IssueResponse> {
export function addIssueComment(
data /*: { issue: string, text: string } */
) /*: Promise<IssueResponse> */ {
const url = '/api/issues/add_comment';
return postJSON(url, data);
}

export function deleteIssueComment(data: { comment: string }): Promise<IssueResponse> {
export function deleteIssueComment(data /*: { comment: string } */) /*: Promise<IssueResponse> */ {
const url = '/api/issues/delete_comment';
return postJSON(url, data);
}

export function editIssueComment(data: { comment: string, text: string }): Promise<IssueResponse> {
export function editIssueComment(
data /*: { comment: string, text: string } */
) /*: Promise<IssueResponse> */ {
const url = '/api/issues/edit_comment';
return postJSON(url, data);
}

export function setIssueAssignee(data: {
export function setIssueAssignee(
data /*: {
issue: string,
assignee?: string
}): Promise<IssueResponse> {
} */
) /*: Promise<IssueResponse> */ {
const url = '/api/issues/assign';
return postJSON(url, data);
}

export function setIssueSeverity(data: { issue: string, severity: string }): Promise<*> {
export function setIssueSeverity(
data /*: { issue: string, severity: string } */
) /*: Promise<*> */ {
const url = '/api/issues/set_severity';
return postJSON(url, data);
}

export function setIssueTags(data: { issue: string, tags: string }): Promise<IssueResponse> {
export function setIssueTags(
data /*: { issue: string, tags: string } */
) /*: Promise<IssueResponse> */ {
const url = '/api/issues/set_tags';
return postJSON(url, data);
}

export function setIssueTransition(data: {
export function setIssueTransition(
data /*: {
issue: string,
transition: string
}): Promise<IssueResponse> {
} */
) /*: Promise<IssueResponse> */ {
const url = '/api/issues/do_transition';
return postJSON(url, data);
}

export function setIssueType(data: { issue: string, type: string }): Promise<IssueResponse> {
export function setIssueType(
data /*: { issue: string, type: string } */
) /*: Promise<IssueResponse> */ {
const url = '/api/issues/set_type';
return postJSON(url, data);
}

export const bulkChangeIssues = (issueKeys: Array<string>, query: {}) =>
post('/api/issues/bulk_change', {
export function bulkChangeIssues(issueKeys /*: Array<string> */, query /*: {} */) {
return post('/api/issues/bulk_change', {
issues: issueKeys.join(),
...query
});
}

+ 19
- 8
server/sonar-web/src/main/js/api/notifications.js 查看文件

@@ -20,6 +20,7 @@
// @flow
import { getJSON, post } from '../helpers/request';

/*::
export type GetNotificationsResponse = {
notifications: Array<{
channel: string,
@@ -32,22 +33,32 @@ export type GetNotificationsResponse = {
globalTypes: Array<string>,
perProjectTypes: Array<string>
};
*/

export const getNotifications = (): Promise<GetNotificationsResponse> =>
getJSON('/api/notifications/list');
export function getNotifications() /*: Promise<GetNotificationsResponse> */ {
return getJSON('/api/notifications/list');
}

export const addNotification = (channel: string, type: string, project?: string): Promise<*> => {
const data: Object = { channel, type };
export function addNotification(
channel /*: string */,
type /*: string */,
project /*: ?string */
) /*: Promise<*> */ {
const data /*: Object */ = { channel, type };
if (project) {
Object.assign(data, { project });
}
return post('/api/notifications/add', data);
};
}

export const removeNotification = (channel: string, type: string, project?: string): Promise<*> => {
const data: Object = { channel, type };
export function removeNotification(
channel /*: string */,
type /*: string */,
project /*: ?string */
) /*: Promise<*> */ {
const data /*: Object */ = { channel, type };
if (project) {
Object.assign(data, { project });
}
return post('/api/notifications/remove', data);
};
}

+ 43
- 23
server/sonar-web/src/main/js/api/organizations.js 查看文件

@@ -19,22 +19,26 @@
*/
// @flow
import { getJSON, post, postJSON } from '../helpers/request';
import type { Organization } from '../store/organizations/duck';
/*:: import type { Organization } from '../store/organizations/duck'; */
import throwGlobalError from '../app/utils/throwGlobalError';

export const getOrganizations = (organizations?: Array<string>) => {
export function getOrganizations(organizations /*: ?Array<string> */) {
const data = {};
if (organizations) {
Object.assign(data, { organizations: organizations.join() });
}
return getJSON('/api/organizations/search', data);
};
}

export const getMyOrganizations = () =>
getJSON('/api/organizations/search_my_organizations').then(r => r.organizations);
export function getMyOrganizations() {
return getJSON('/api/organizations/search_my_organizations').then(r => r.organizations);
}

/*::
type GetOrganizationType = null | Organization;
*/

/*::
type GetOrganizationNavigation = {
canAdmin: boolean,
canDelete: boolean,
@@ -43,39 +47,55 @@ type GetOrganizationNavigation = {
pages: Array<{ key: string, name: string }>,
adminPages: Array<{ key: string, name: string }>
};
*/

export const getOrganization = (key: string): Promise<GetOrganizationType> => {
export function getOrganization(key /*: string */) /*: Promise<GetOrganizationType> */ {
return getOrganizations([key])
.then(r => r.organizations.find(o => o.key === key))
.catch(throwGlobalError);
};
}

export const getOrganizationNavigation = (key: string): Promise<GetOrganizationNavigation> => {
export function getOrganizationNavigation(
key /*: string */
) /*: Promise<GetOrganizationNavigation> */ {
return getJSON('/api/navigation/organization', { organization: key }).then(r => r.organization);
};
}

export const createOrganization = (fields: {}): Promise<Organization> =>
postJSON('/api/organizations/create', fields).then(r => r.organization, throwGlobalError);
export function createOrganization(fields /*: {} */) /*: Promise<Organization> */ {
return postJSON('/api/organizations/create', fields).then(r => r.organization, throwGlobalError);
}

export const updateOrganization = (key: string, changes: {}) =>
post('/api/organizations/update', { key, ...changes });
export function updateOrganization(key /*: string */, changes /*: {} */) {
return post('/api/organizations/update', { key, ...changes });
}

export const deleteOrganization = (key: string) =>
post('/api/organizations/delete', { key }).catch(throwGlobalError);
export function deleteOrganization(key /*: string */) {
return post('/api/organizations/delete', { key }).catch(throwGlobalError);
}

export const searchMembers = (data: {
export function searchMembers(
data /*: {
organization?: string,
p?: number,
ps?: number,
q?: string,
selected?: string
}) => getJSON('/api/organizations/search_members', data);
} */
) {
return getJSON('/api/organizations/search_members', data);
}

export const addMember = (data: { login: string, organization: string }) =>
postJSON('/api/organizations/add_member', data).then(r => r.user);
export function addMember(data /*: { login: string, organization: string } */) {
return postJSON('/api/organizations/add_member', data).then(r => r.user);
}

export const removeMember = (data: { login: string, organization: string }) =>
post('/api/organizations/remove_member', data);
export function removeMember(data /*: { login: string, organization: string } */) {
return post('/api/organizations/remove_member', data);
}

export const changeProjectVisibility = (organization: string, projectVisibility: string) =>
post('/api/organizations/update_project_visibility', { organization, projectVisibility });
export function changeProjectVisibility(
organization /*: string */,
projectVisibility /*: string */
) {
return post('/api/organizations/update_project_visibility', { organization, projectVisibility });
}

+ 80
- 67
server/sonar-web/src/main/js/api/permissions.js 查看文件

@@ -23,13 +23,13 @@ import { getJSON, post, postJSON } from '../helpers/request';
const PAGE_SIZE = 100;

export function grantPermissionToUser(
projectKey: string | null,
login: string,
permission: string,
organization?: string
projectKey /*: string | null */,
login /*: string */,
permission /*: string */,
organization /*: ?string */
) {
const url = '/api/permissions/add_user';
const data: Object = { login, permission };
const data /*: Object */ = { login, permission };
if (projectKey) {
data.projectKey = projectKey;
}
@@ -40,13 +40,13 @@ export function grantPermissionToUser(
}

export function revokePermissionFromUser(
projectKey: string | null,
login: string,
permission: string,
organization?: string
projectKey /*: string | null */,
login /*: string */,
permission /*: string */,
organization /*: ?string */
) {
const url = '/api/permissions/remove_user';
const data: Object = { login, permission };
const data /*: Object */ = { login, permission };
if (projectKey) {
data.projectKey = projectKey;
}
@@ -57,13 +57,13 @@ export function revokePermissionFromUser(
}

export function grantPermissionToGroup(
projectKey: string | null,
groupName: string,
permission: string,
organization?: string
projectKey /*: string | null */,
groupName /*: string */,
permission /*: string */,
organization /*: ?string */
) {
const url = '/api/permissions/add_group';
const data: Object = { groupName, permission };
const data /*: Object */ = { groupName, permission };
if (projectKey) {
data.projectKey = projectKey;
}
@@ -74,13 +74,13 @@ export function grantPermissionToGroup(
}

export function revokePermissionFromGroup(
projectKey: string | null,
groupName: string,
permission: string,
organization?: string
projectKey /*: string | null */,
groupName /*: string */,
permission /*: string */,
organization /*: ?string */
) {
const url = '/api/permissions/remove_group';
const data: Object = { groupName, permission };
const data /*: Object */ = { groupName, permission };
if (projectKey) {
data.projectKey = projectKey;
}
@@ -94,19 +94,22 @@ export function revokePermissionFromGroup(
* Get list of permission templates
* @returns {Promise}
*/
export function getPermissionTemplates(organization?: string) {
export function getPermissionTemplates(organization /*: ?string */) {
const url = '/api/permissions/search_templates';
return organization ? getJSON(url, { organization }) : getJSON(url);
}

export const createPermissionTemplate = (data: Object) =>
postJSON('/api/permissions/create_template', data);
export function createPermissionTemplate(data /*: Object */) {
return postJSON('/api/permissions/create_template', data);
}

export const updatePermissionTemplate = (data: Object) =>
post('/api/permissions/update_template', data);
export function updatePermissionTemplate(data /*: Object */) {
return post('/api/permissions/update_template', data);
}

export const deletePermissionTemplate = (data: Object) =>
post('/api/permissions/delete_template', data);
export function deletePermissionTemplate(data /*: Object */) {
return post('/api/permissions/delete_template', data);
}

/**
* Set default permission template for a given qualifier
@@ -114,72 +117,79 @@ export const deletePermissionTemplate = (data: Object) =>
* @param {string} qualifier
* @returns {Promise}
*/
export function setDefaultPermissionTemplate(templateId: string, qualifier: string) {
export function setDefaultPermissionTemplate(templateId /*: string */, qualifier /*: string */) {
const url = '/api/permissions/set_default_template';
const data = { templateId, qualifier };
return post(url, data);
}

export function applyTemplateToProject(data: Object) {
export function applyTemplateToProject(data /*: Object */) {
const url = '/api/permissions/apply_template';
return post(url, data);
}

export function bulkApplyTemplate(data: Object) {
export function bulkApplyTemplate(data /*: Object */) {
const url = '/api/permissions/bulk_apply_template';
return post(url, data);
}

export function grantTemplatePermissionToUser(data: {
export function grantTemplatePermissionToUser(
data /*: {
templateId: string,
login: string,
permission: string,
organization?: string
}) {
} */
) {
const url = '/api/permissions/add_user_to_template';
return post(url, data);
}

export function revokeTemplatePermissionFromUser(data: {
export function revokeTemplatePermissionFromUser(
data /*: {
templateId: string,
login: string,
permission: string,
organization?: string
}) {
} */
) {
const url = '/api/permissions/remove_user_from_template';
return post(url, data);
}

export function grantTemplatePermissionToGroup(data: Object) {
export function grantTemplatePermissionToGroup(data /*: Object */) {
const url = '/api/permissions/add_group_to_template';
return post(url, data);
}

export function revokeTemplatePermissionFromGroup(data: Object) {
export function revokeTemplatePermissionFromGroup(data /*: Object */) {
const url = '/api/permissions/remove_group_from_template';
return post(url, data);
}

export function addProjectCreatorToTemplate(templateId: string, permission: string) {
export function addProjectCreatorToTemplate(templateId /*: string */, permission /*: string */) {
const url = '/api/permissions/add_project_creator_to_template';
const data = { templateId, permission };
return post(url, data);
}

export function removeProjectCreatorFromTemplate(templateId: string, permission: string) {
export function removeProjectCreatorFromTemplate(
templateId /*: string */,
permission /*: string */
) {
const url = '/api/permissions/remove_project_creator_from_template';
const data = { templateId, permission };
return post(url, data);
}

export function getPermissionsUsersForComponent(
projectKey: string,
query?: string,
permission?: string,
organization?: string
projectKey /*: string */,
query /*: ?string */,
permission /*: ?string */,
organization /*: ?string */
) {
const url = '/api/permissions/users';
const data: Object = { projectKey, ps: PAGE_SIZE };
const data /*: Object */ = { projectKey, ps: PAGE_SIZE };
if (query) {
data.q = query;
}
@@ -193,13 +203,13 @@ export function getPermissionsUsersForComponent(
}

export function getPermissionsGroupsForComponent(
projectKey: string,
query: string = '',
permission?: string,
organization?: string
projectKey /*: string */,
query /*: string */ = '',
permission /*: ?string */,
organization /*: ?string */
) {
const url = '/api/permissions/groups';
const data: Object = { projectKey, ps: PAGE_SIZE };
const data /*: Object */ = { projectKey, ps: PAGE_SIZE };
if (query) {
data.q = query;
}
@@ -213,12 +223,12 @@ export function getPermissionsGroupsForComponent(
}

export function getGlobalPermissionsUsers(
query?: string,
permission?: string,
organization?: string
query /*: ?string */,
permission /*: ?string */,
organization /*: ?string */
) {
const url = '/api/permissions/users';
const data: Object = { ps: PAGE_SIZE };
const data /*: Object */ = { ps: PAGE_SIZE };
if (query) {
data.q = query;
}
@@ -232,12 +242,12 @@ export function getGlobalPermissionsUsers(
}

export function getGlobalPermissionsGroups(
query?: string,
permission?: string,
organization?: string
query /*: ?string */,
permission /*: ?string */,
organization /*: ?string */
) {
const url = '/api/permissions/groups';
const data: Object = { ps: PAGE_SIZE };
const data /*: Object */ = { ps: PAGE_SIZE };
if (query) {
data.q = query;
}
@@ -251,13 +261,13 @@ export function getGlobalPermissionsGroups(
}

export function getPermissionTemplateUsers(
templateId: string,
query?: string,
permission?: string,
organization?: string
templateId /*: string */,
query /*: ?string */,
permission /*: ?string */,
organization /*: ?string */
) {
const url = '/api/permissions/template_users';
const data: Object = { templateId, ps: PAGE_SIZE };
const data /*: Object */ = { templateId, ps: PAGE_SIZE };
if (query) {
data.q = query;
}
@@ -271,13 +281,13 @@ export function getPermissionTemplateUsers(
}

export function getPermissionTemplateGroups(
templateId: string,
query?: string,
permission?: string,
organization?: string
templateId /*: string */,
query /*: ?string */,
permission /*: ?string */,
organization /*: ?string */
) {
const url = '/api/permissions/template_groups';
const data: Object = { templateId, ps: PAGE_SIZE };
const data /*: Object */ = { templateId, ps: PAGE_SIZE };
if (query) {
data.q = query;
}
@@ -290,7 +300,10 @@ export function getPermissionTemplateGroups(
return getJSON(url, data).then(r => r.groups);
}

export function changeProjectVisibility(project: string, visibility: string): Promise<void> {
export function changeProjectVisibility(
project /*: string */,
visibility /*: string */
) /*: Promise<void> */ {
const url = '/api/projects/update_visibility';
const data = { project, visibility };
return post(url, data);

+ 32
- 23
server/sonar-web/src/main/js/api/projectActivity.js 查看文件

@@ -21,6 +21,7 @@
import { getJSON, postJSON, post } from '../helpers/request';
import throwGlobalError from '../app/utils/throwGlobalError';

/*::
type GetProjectActivityResponse = {
analyses: Array<Object>,
paging: {
@@ -29,19 +30,24 @@ type GetProjectActivityResponse = {
pageSize: number
}
};
*/

/*::
type GetProjectActivityOptions = {
project: string,
category?: ?string,
p?: ?number,
ps?: ?number
};
*/

export const getProjectActivity = (
data: GetProjectActivityOptions
): Promise<GetProjectActivityResponse> =>
getJSON('/api/project_analyses/search', data).catch(throwGlobalError);
export function getProjectActivity(
data /*: GetProjectActivityOptions */
) /*: Promise<GetProjectActivityResponse> */ {
return getJSON('/api/project_analyses/search', data).catch(throwGlobalError);
}

/*::
type CreateEventResponse = {
analysis: string,
key: string,
@@ -49,14 +55,15 @@ type CreateEventResponse = {
category: string,
description?: string
};
*/

export const createEvent = (
analysis: string,
name: string,
category?: string,
description?: string
): Promise<CreateEventResponse> => {
const data: Object = { analysis, name };
export function createEvent(
analysis /*: string */,
name /*: string */,
category /*: ?string */,
description /*: ?string */
) /*: Promise<CreateEventResponse> */ {
const data /*: Object */ = { analysis, name };
if (category) {
data.category = category;
}
@@ -64,17 +71,18 @@ export const createEvent = (
data.description = description;
}
return postJSON('/api/project_analyses/create_event', data).then(r => r.event, throwGlobalError);
};
}

export const deleteEvent = (event: string): Promise<*> =>
post('/api/project_analyses/delete_event', { event }).catch(throwGlobalError);
export function deleteEvent(event /*: string */) /*: Promise<*> */ {
return post('/api/project_analyses/delete_event', { event }).catch(throwGlobalError);
}

export const changeEvent = (
event: string,
name: ?string,
description: ?string
): Promise<CreateEventResponse> => {
const data: Object = { event };
export function changeEvent(
event /*: string */,
name /*: ?string */,
description /*: ?string */
) /*: Promise<CreateEventResponse> */ {
const data /*: Object */ = { event };
if (name) {
data.name = name;
}
@@ -82,7 +90,8 @@ export const changeEvent = (
data.description = description;
}
return postJSON('/api/project_analyses/update_event', data).then(r => r.event, throwGlobalError);
};
}

export const deleteAnalysis = (analysis: string): Promise<*> =>
post('/api/project_analyses/delete', { analysis }).catch(throwGlobalError);
export function deleteAnalysis(analysis /*: string */) /*: Promise<*> */ {
return post('/api/project_analyses/delete', { analysis }).catch(throwGlobalError);
}

+ 15
- 15
server/sonar-web/src/main/js/api/quality-profiles.js 查看文件

@@ -20,17 +20,17 @@
// @flow
import { request, checkStatus, parseJSON, getJSON, post, postJSON } from '../helpers/request';

export function searchQualityProfiles(data: { organization?: string, projectKey?: string }) {
export function searchQualityProfiles(data /*: { organization?: string, projectKey?: string } */) {
const url = '/api/qualityprofiles/search';
return getJSON(url, data).then(r => r.profiles);
}

export function getQualityProfiles(data: { compareToSonarWay?: boolean, profile: string }) {
export function getQualityProfiles(data /*: { compareToSonarWay?: boolean, profile: string } */) {
const url = '/api/qualityprofiles/show';
return getJSON(url, data);
}

export function createQualityProfile(data: Object) {
export function createQualityProfile(data /*: Object */) {
return request('/api/qualityprofiles/create')
.setMethod('post')
.setData(data)
@@ -39,7 +39,7 @@ export function createQualityProfile(data: Object) {
.then(parseJSON);
}

export function restoreQualityProfile(data: Object) {
export function restoreQualityProfile(data /*: Object */) {
return request('/api/qualityprofiles/restore')
.setMethod('post')
.setData(data)
@@ -48,42 +48,42 @@ export function restoreQualityProfile(data: Object) {
.then(parseJSON);
}

export function getProfileProjects(data: Object) {
export function getProfileProjects(data /*: Object */) {
const url = '/api/qualityprofiles/projects';
return getJSON(url, data);
}

export function getProfileInheritance(profileKey: string) {
export function getProfileInheritance(profileKey /*: string */) {
const url = '/api/qualityprofiles/inheritance';
const data = { profileKey };
return getJSON(url, data);
}

export function setDefaultProfile(profileKey: string) {
export function setDefaultProfile(profileKey /*: string */) {
const url = '/api/qualityprofiles/set_default';
const data = { profileKey };
return post(url, data);
}

export function renameProfile(key: string, name: string) {
export function renameProfile(key /*: string */, name /*: string */) {
const url = '/api/qualityprofiles/rename';
const data = { key, name };
return post(url, data);
}

export function copyProfile(fromKey: string, toName: string) {
export function copyProfile(fromKey /*: string */, toName /*: string */) {
const url = '/api/qualityprofiles/copy';
const data = { fromKey, toName };
return postJSON(url, data);
}

export function deleteProfile(profileKey: string) {
export function deleteProfile(profileKey /*: string */) {
const url = '/api/qualityprofiles/delete';
const data = { profileKey };
return post(url, data);
}

export function changeProfileParent(profileKey: string, parentKey: string) {
export function changeProfileParent(profileKey /*: string */, parentKey /*: string */) {
const url = '/api/qualityprofiles/change_parent';
const data = { profileKey, parentKey };
return post(url, data);
@@ -99,24 +99,24 @@ export function getExporters() {
return getJSON(url).then(r => r.exporters);
}

export function getProfileChangelog(data: Object) {
export function getProfileChangelog(data /*: Object */) {
const url = '/api/qualityprofiles/changelog';
return getJSON(url, data);
}

export function compareProfiles(leftKey: string, rightKey: string) {
export function compareProfiles(leftKey /*: string */, rightKey /*: string */) {
const url = '/api/qualityprofiles/compare';
const data = { leftKey, rightKey };
return getJSON(url, data);
}

export function associateProject(profileKey: string, projectKey: string) {
export function associateProject(profileKey /*: string */, projectKey /*: string */) {
const url = '/api/qualityprofiles/add_project';
const data = { profileKey, projectKey };
return post(url, data);
}

export function dissociateProject(profileKey: string, projectKey: string) {
export function dissociateProject(profileKey /*: string */, projectKey /*: string */) {
const url = '/api/qualityprofiles/remove_project';
const data = { profileKey, projectKey };
return post(url, data);

+ 17
- 13
server/sonar-web/src/main/js/api/time-machine.js 查看文件

@@ -20,6 +20,7 @@
// @flow
import { getJSON } from '../helpers/request';

/*::
type Response = {
measures: Array<{
metric: string,
@@ -34,26 +35,28 @@ type Response = {
total: number
}
};
*/

export const getTimeMachineData = (
component: string,
metrics: Array<string>,
other?: { p?: number, ps?: number, from?: string, to?: string }
): Promise<Response> =>
getJSON('/api/measures/search_history', {
export function getTimeMachineData(
component /*: string */,
metrics /*: Array<string> */,
other /*: ?{ p?: number, ps?: number, from?: string, to?: string } */
) /*: Promise<Response> */ {
return getJSON('/api/measures/search_history', {
component,
metrics: metrics.join(),
ps: 1000,
...other
});
}

export const getAllTimeMachineData = (
component: string,
metrics: Array<string>,
other?: { p?: number, from?: string, to?: string },
prev?: Response
): Promise<Response> =>
getTimeMachineData(component, metrics, { ...other, ps: 1000 }).then((r: Response) => {
export function getAllTimeMachineData(
component /*: string */,
metrics /*: Array<string> */,
other /*: ?{ p?: number, from?: string, to?: string } */,
prev /*: ?Response */
) /*: Promise<Response> */ {
return getTimeMachineData(component, metrics, { ...other, ps: 1000 }).then(r => {
const result = prev
? {
measures: prev.measures.map((measure, idx) => ({
@@ -74,3 +77,4 @@ export const getAllTimeMachineData = (
result
);
});
}

+ 7
- 7
server/sonar-web/src/main/js/api/user-tokens.js 查看文件

@@ -26,7 +26,7 @@ import throwGlobalError from '../app/utils/throwGlobalError';
* @param {string} login
* @returns {Promise}
*/
export function getTokens(login: string) {
export function getTokens(login /*: string */) {
const url = '/api/user_tokens/search';
const data = { login };
return getJSON(url, data).then(r => r.userTokens);
@@ -39,11 +39,11 @@ export function getTokens(login: string) {
* @returns {Promise}
*/
export function generateToken(
tokenName: string,
userLogin?: string
): Promise<{ name: string, token: string }> {
tokenName /*: string */,
userLogin /*: ?string */
) /*: Promise<{ name: string, token: string }> */ {
const url = '/api/user_tokens/generate';
const data: { [string]: string } = { name: tokenName };
const data /*: { [string]: string } */ = { name: tokenName };
if (userLogin) {
data.login = userLogin;
}
@@ -56,9 +56,9 @@ export function generateToken(
* @param {string} tokenName
* @returns {Promise}
*/
export function revokeToken(tokenName: string, userLogin?: string) {
export function revokeToken(tokenName /*: string */, userLogin /*: ?string */) {
const url = '/api/user_tokens/revoke';
const data: { [string]: string } = { name: tokenName };
const data /*: { [string]: string } */ = { name: tokenName };
if (userLogin) {
data.login = userLogin;
}

+ 12
- 6
server/sonar-web/src/main/js/api/user_groups.js 查看文件

@@ -20,33 +20,39 @@
//@flow
import { getJSON, post } from '../helpers/request';

export function searchUsersGroups(data: {
export function searchUsersGroups(
data /*: {
f?: string,
organization?: string,
p?: number,
ps?: number,
q?: string
}) {
} */
) {
const url = '/api/user_groups/search';
return getJSON(url, data);
}

export function addUserToGroup(data: {
export function addUserToGroup(
data /*: {
id?: string,
name?: string,
login?: string,
organization?: string
}) {
} */
) {
const url = '/api/user_groups/add_user';
return post(url, data);
}

export function removeUserFromGroup(data: {
export function removeUserFromGroup(
data /*: {
id?: string,
name?: string,
login?: string,
organization?: string
}) {
} */
) {
const url = '/api/user_groups/remove_user';
return post(url, data);
}

+ 14
- 7
server/sonar-web/src/main/js/api/users.js 查看文件

@@ -25,18 +25,25 @@ export function getCurrentUser() {
return getJSON(url);
}

export function changePassword(login: string, password: string, previousPassword?: string) {
export function changePassword(
login /*: string */,
password /*: string */,
previousPassword /*: ?string */
) {
const url = '/api/users/change_password';
const data: { login: string, password: string, previousPassword?: string } = { login, password };
const data /*: { login: string, password: string, previousPassword?: string } */ = {
login,
password
};
if (previousPassword != null) {
data.previousPassword = previousPassword;
}
return post(url, data);
}

export function getUserGroups(login: string, organization?: string) {
export function getUserGroups(login /*: string */, organization /*: ?string */) {
const url = '/api/users/groups';
const data: { login: string, organization?: string, q?: string } = { login };
const data /*: { login: string, organization?: string, q?: string } */ = { login };
if (organization) {
data.organization = organization;
}
@@ -48,15 +55,15 @@ export function getIdentityProviders() {
return getJSON(url);
}

export function searchUsers(query: string, pageSize?: number) {
export function searchUsers(query /*: string */, pageSize /*: ?number */) {
const url = '/api/users/search';
const data: { q: string, ps?: number } = { q: query };
const data /*: { q: string, ps?: number } */ = { q: query };
if (pageSize != null) {
data.ps = pageSize;
}
return getJSON(url, data);
}

export function skipOnboarding(): Promise<void> {
export function skipOnboarding() /*: Promise<void> */ {
return post('/api/users/skip_onboarding_tutorial');
}

+ 11
- 2
server/sonar-web/src/main/js/api/web-api.js 查看文件

@@ -20,6 +20,7 @@
// @flow
import { getJSON } from '../helpers/request';

/*::
export type Param = {
key: string,
defaultValue?: string,
@@ -32,7 +33,9 @@ export type Param = {
possibleValues?: Array<string>,
required: boolean
};
*/

/*::
export type Action = {
key: string,
description: string,
@@ -47,7 +50,9 @@ export type Action = {
}>,
params?: Array<Param>
};
*/

/*::
export type Domain = {
actions: Array<Action>,
description: string,
@@ -55,8 +60,9 @@ export type Domain = {
internal: boolean,
path: string
};
*/

export function fetchWebApi(showInternal: boolean = true): Promise<Array<Domain>> {
export function fetchWebApi(showInternal /*: boolean */ = true) /*: Promise<Array<Domain>> */ {
const url = '/api/webservices/list';
const data = { include_internals: showInternal };

@@ -70,7 +76,10 @@ export function fetchWebApi(showInternal: boolean = true): Promise<Array<Domain>
);
}

export function fetchResponseExample(domain: string, action: string): Promise<{ example: string }> {
export function fetchResponseExample(
domain /*: string */,
action /*: string */
) /*: Promise<{ example: string }> */ {
const url = '/api/webservices/response_example';
const data = { controller: domain, action };


+ 1
- 1
server/sonar-web/src/main/js/app/components/App.js 查看文件

@@ -26,7 +26,7 @@ import { fetchCurrentUser } from '../../store/users/actions';
import { fetchLanguages, fetchAppState } from '../../store/rootActions';

class App extends React.PureComponent {
mounted: boolean;
/*:: mounted: boolean; */

static propTypes = {
fetchAppState: PropTypes.func.isRequired,

+ 1
- 1
server/sonar-web/src/main/js/app/components/GlobalContainer.js 查看文件

@@ -23,7 +23,7 @@ import GlobalNav from './nav/global/GlobalNav';
import GlobalFooterContainer from './GlobalFooterContainer';
import GlobalMessagesContainer from './GlobalMessagesContainer';

export default function GlobalContainer(props: Object) {
export default function GlobalContainer(props /*: Object */) {
// it is important to pass `location` down to `GlobalNav` to trigger render on url change

return (

+ 5
- 6
server/sonar-web/src/main/js/app/components/GlobalFooter.js 查看文件

@@ -24,19 +24,18 @@ import GlobalFooterForSonarQubeDotCom from './GlobalFooterForSonarQubeDotCom';
import GlobalFooterBranding from './GlobalFooterBranding';
import { translate, translateWithParameters } from '../../helpers/l10n';

/*::
type Props = {
hideLoggedInInfo?: boolean,
productionDatabase: boolean,
sonarqubeDotCom?: { value: string },
sonarqubeVersion?: string
};
*/

export default function GlobalFooter({
hideLoggedInInfo,
productionDatabase,
sonarqubeDotCom,
sonarqubeVersion
}: Props) {
export default function GlobalFooter(
{ hideLoggedInInfo, productionDatabase, sonarqubeDotCom, sonarqubeVersion } /*: Props */
) {
if (sonarqubeDotCom && sonarqubeDotCom.value === 'true') {
return <GlobalFooterForSonarQubeDotCom hideLoggedInInfo={hideLoggedInInfo} />;
}

+ 1
- 1
server/sonar-web/src/main/js/app/components/LocalizationContainer.js 查看文件

@@ -23,7 +23,7 @@ import GlobalLoading from './GlobalLoading';
import { requestMessages } from '../../helpers/l10n';

export default class LocalizationContainer extends React.PureComponent {
mounted: boolean;
/*:: mounted: boolean; */

state = {
loading: true

+ 2
- 0
server/sonar-web/src/main/js/app/components/MigrationContainer.js 查看文件

@@ -24,10 +24,12 @@ import GlobalLoading from './GlobalLoading';
import { getSystemStatus } from '../../api/system';

class MigrationContainer extends React.PureComponent {
/*::
props: {
children?: React.Element<*>,
router: { push: (path: string) => void }
};
*/

state = {
loading: true

+ 2
- 0
server/sonar-web/src/main/js/app/components/ProjectAdminContainer.js 查看文件

@@ -23,6 +23,7 @@ import { getComponent } from '../../store/rootReducer';
import handleRequiredAuthorization from '../utils/handleRequiredAuthorization';

class ProjectAdminContainer extends React.PureComponent {
/*::
props: {
project: {
configuration?: {
@@ -30,6 +31,7 @@ class ProjectAdminContainer extends React.PureComponent {
}
}
};
*/

componentDidMount() {
this.checkPermissions();

+ 3
- 1
server/sonar-web/src/main/js/app/components/ProjectContainer.js 查看文件

@@ -29,6 +29,7 @@ import { parseError } from '../../apps/code/utils';
import handleRequiredAuthorization from '../utils/handleRequiredAuthorization';

class ProjectContainer extends React.PureComponent {
/*::
props: {
addGlobalErrorMessage: (message: string) => void,
children?: React.Element<*>,
@@ -43,6 +44,7 @@ class ProjectContainer extends React.PureComponent {
fetchProject: string => Promise<*>,
receiveComponents: (Array<*>) => void
};
*/

componentDidMount() {
this.fetchProject();
@@ -64,7 +66,7 @@ class ProjectContainer extends React.PureComponent {
});
}

handleProjectChange = (changes: {}) => {
handleProjectChange = (changes /*: {} */) => {
this.props.receiveComponents([{ ...this.props.project, ...changes }]);
};


+ 11
- 9
server/sonar-web/src/main/js/app/components/RecentHistory.js 查看文件

@@ -21,15 +21,17 @@
const STORAGE_KEY = 'sonar_recent_history';
const HISTORY_LIMIT = 10;

/*::
type History = Array<{
key: string,
name: string,
icon: string,
organization?: string
}>;
*/

export default class RecentHistory {
static get(): History {
static get() /*: History */ {
if (!window.localStorage) {
return [];
}
@@ -47,24 +49,24 @@ export default class RecentHistory {
return history;
}

static set(newHistory: History): void {
static set(newHistory /*: History */) /*: void */ {
if (window.localStorage) {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(newHistory));
}
}

static clear(): void {
static clear() /*: void */ {
if (window.localStorage) {
window.localStorage.removeItem(STORAGE_KEY);
}
}

static add(
componentKey: string,
componentName: string,
icon: string,
organization?: string
): void {
componentKey /*: string */,
componentName /*: string */,
icon /*: string */,
organization /*: string | void */
) /*: void */ {
const sonarHistory = RecentHistory.get();
const newEntry = { key: componentKey, name: componentName, icon, organization };
let newHistory = sonarHistory.filter(entry => entry.key !== newEntry.key);
@@ -73,7 +75,7 @@ export default class RecentHistory {
RecentHistory.set(newHistory);
}

static remove(componentKey: string): void {
static remove(componentKey /*: string */) /*: void */ {
const history = RecentHistory.get();
const newHistory = history.filter(entry => entry.key !== componentKey);
RecentHistory.set(newHistory);

+ 3
- 1
server/sonar-web/src/main/js/app/components/SimpleContainer.js 查看文件

@@ -22,13 +22,15 @@ import React from 'react';
import GlobalFooterContainer from './GlobalFooterContainer';
import NavBar from '../../components/nav/NavBar';

/*::
type Props = {
children?: React.Element<*> | Array<React.Element<*>>,
hideLoggedInInfo?: boolean
};
*/

export default class SimpleContainer extends React.PureComponent {
props: Props;
/*:: props: Props; */

componentDidMount() {
const html = document.querySelector('html');

+ 7
- 5
server/sonar-web/src/main/js/app/components/extensions/Extension.js 查看文件

@@ -28,6 +28,7 @@ import { translate } from '../../../helpers/l10n';
import { getExtensionStart } from './utils';
import getStore from '../../utils/getStore';

/*::
type Props = {
currentUser: Object,
extension: {
@@ -39,17 +40,18 @@ type Props = {
options?: {},
router: Object
};
*/

class Extension extends React.PureComponent {
container: Object;
props: Props;
stop: ?Function;
/*:: container: Object; */
/*:: props: Props; */
/*:: stop: ?Function; */

componentDidMount() {
this.startExtension();
}

componentDidUpdate(prevProps: Props) {
componentDidUpdate(prevProps /*: Props */) {
if (prevProps.extension !== this.props.extension) {
this.stopExtension();
this.startExtension();
@@ -66,7 +68,7 @@ class Extension extends React.PureComponent {
this.stopExtension();
}

handleStart = (start: Function) => {
handleStart = (start /*: Function */) => {
const store = getStore();
this.stop = start({
store,

+ 3
- 1
server/sonar-web/src/main/js/app/components/extensions/GlobalAdminPageExtension.js 查看文件

@@ -24,6 +24,7 @@ import Extension from './Extension';
import ExtensionNotFound from './ExtensionNotFound';
import { getAppState } from '../../../store/rootReducer';

/*::
type Props = {
adminPages: Array<{ key: string }>,
params: {
@@ -31,8 +32,9 @@ type Props = {
pluginKey: string
}
};
*/

function GlobalAdminPageExtension(props: Props) {
function GlobalAdminPageExtension(props /*: Props */) {
const { extensionKey, pluginKey } = props.params;
const extension = props.adminPages.find(p => p.key === `${pluginKey}/${extensionKey}`);
return extension ? <Extension extension={extension} /> : <ExtensionNotFound />;

+ 3
- 1
server/sonar-web/src/main/js/app/components/extensions/GlobalPageExtension.js 查看文件

@@ -24,6 +24,7 @@ import Extension from './Extension';
import ExtensionNotFound from './ExtensionNotFound';
import { getAppState } from '../../../store/rootReducer';

/*::
type Props = {
globalPages: Array<{ key: string }>,
params: {
@@ -31,8 +32,9 @@ type Props = {
pluginKey: string
}
};
*/

function GlobalPageExtension(props: Props) {
function GlobalPageExtension(props /*: Props */) {
const { extensionKey, pluginKey } = props.params;
const extension = props.globalPages.find(p => p.key === `${pluginKey}/${extensionKey}`);
return extension ? <Extension extension={extension} /> : <ExtensionNotFound />;

+ 5
- 3
server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.js 查看文件

@@ -24,8 +24,9 @@ import Extension from './Extension';
import ExtensionNotFound from './ExtensionNotFound';
import { getOrganizationByKey } from '../../../store/rootReducer';
import { fetchOrganization } from '../../../apps/organizations/actions';
import type { Organization } from '../../../store/organizations/duck';
/*:: import type { Organization } from '../../../store/organizations/duck'; */

/*::
type Props = {
fetchOrganization: string => void,
location: {},
@@ -36,9 +37,10 @@ type Props = {
pluginKey: string
}
};
*/

class OrganizationPageExtension extends React.PureComponent {
props: Props;
/*:: props: Props; */

refreshOrganization = () => this.props.fetchOrganization(this.props.organization.key);

@@ -62,7 +64,7 @@ class OrganizationPageExtension extends React.PureComponent {
}
}

const mapStateToProps = (state, ownProps: Props) => ({
const mapStateToProps = (state, ownProps /*: Props */) => ({
organization: getOrganizationByKey(state, ownProps.params.organizationKey)
});


+ 1
- 1
server/sonar-web/src/main/js/app/components/extensions/PortfoliosPage.js 查看文件

@@ -21,7 +21,7 @@
import React from 'react';
import GlobalPageExtension from './GlobalPageExtension';

export default function PortfoliosPage(props: Object) {
export default function PortfoliosPage(props /*: Object */) {
return (
<div>
<GlobalPageExtension

+ 4
- 2
server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.js 查看文件

@@ -25,6 +25,7 @@ import ExtensionNotFound from './ExtensionNotFound';
import { getComponent } from '../../../store/rootReducer';
import { addGlobalErrorMessage } from '../../../store/globalMessages/duck';

/*::
type Props = {
component: {
configuration?: {
@@ -37,8 +38,9 @@ type Props = {
pluginKey: string
}
};
*/

function ProjectAdminPageExtension(props: Props) {
function ProjectAdminPageExtension(props /*: Props */) {
const { extensionKey, pluginKey } = props.params;
const { component } = props;
const extension =
@@ -49,7 +51,7 @@ function ProjectAdminPageExtension(props: Props) {
: <ExtensionNotFound />;
}

const mapStateToProps = (state, ownProps: Props) => ({
const mapStateToProps = (state, ownProps /*: Props */) => ({
component: getComponent(state, ownProps.location.query.id)
});


+ 4
- 2
server/sonar-web/src/main/js/app/components/extensions/ProjectPageExtension.js 查看文件

@@ -25,6 +25,7 @@ import ExtensionNotFound from './ExtensionNotFound';
import { getComponent } from '../../../store/rootReducer';
import { addGlobalErrorMessage } from '../../../store/globalMessages/duck';

/*::
type Props = {
component: {
extensions: Array<{ key: string }>
@@ -35,8 +36,9 @@ type Props = {
pluginKey: string
}
};
*/

function ProjectPageExtension(props: Props) {
function ProjectPageExtension(props /*: Props */) {
const { extensionKey, pluginKey } = props.params;
const { component } = props;
const extension = component.extensions.find(p => p.key === `${pluginKey}/${extensionKey}`);
@@ -45,7 +47,7 @@ function ProjectPageExtension(props: Props) {
: <ExtensionNotFound />;
}

const mapStateToProps = (state, ownProps: Props) => ({
const mapStateToProps = (state, ownProps /*: Props */) => ({
component: getComponent(state, ownProps.location.query.id)
});


+ 1
- 1
server/sonar-web/src/main/js/app/components/extensions/ViewDashboard.js 查看文件

@@ -21,7 +21,7 @@
import React from 'react';
import ProjectPageExtension from './ProjectPageExtension';

export default function ViewDashboard(props: Object) {
export default function ViewDashboard(props /*: Object */) {
return (
<ProjectPageExtension
location={props.location}

+ 5
- 4
server/sonar-web/src/main/js/app/components/extensions/utils.js 查看文件

@@ -20,17 +20,17 @@
// @flow
import { getExtensionFromCache } from '../../utils/installExtensionsHandler';

const installScript = (key: string) => {
function installScript(key /*: string */) {
return new Promise(resolve => {
const scriptTag = document.createElement('script');
scriptTag.src = `${window.baseUrl}/static/${key}.js`;
scriptTag.onload = resolve;
document.getElementsByTagName('body')[0].appendChild(scriptTag);
});
};
}

export const getExtensionStart = (key: string) =>
new Promise((resolve, reject) => {
export function getExtensionStart(key /*: string */) {
return new Promise((resolve, reject) => {
const fromCache = getExtensionFromCache(key);
if (fromCache) {
return resolve(fromCache);
@@ -45,3 +45,4 @@ export const getExtensionStart = (key: string) =>
}
});
});
}

+ 9
- 5
server/sonar-web/src/main/js/app/components/help/GlobalHelp.js 查看文件

@@ -27,27 +27,31 @@ import ShortcutsHelp from './ShortcutsHelp';
import TutorialsHelp from './TutorialsHelp';
import { translate } from '../../../helpers/l10n';

/*::
type Props = {
currentUser: { isLoggedIn: boolean },
onClose: () => void,
onTutorialSelect: () => void,
sonarCloud?: boolean
};
*/

/*::
type State = {
section: string
};
*/

export default class GlobalHelp extends React.PureComponent {
props: Props;
state: State = { section: 'shortcuts' };
/*:: props: Props; */
state /*: State */ = { section: 'shortcuts' };

handleCloseClick = (event: Event) => {
handleCloseClick = (event /*: Event */) => {
event.preventDefault();
this.props.onClose();
};

handleSectionClick = (event: Event & { currentTarget: HTMLElement }) => {
handleSectionClick = (event /*: Event & { currentTarget: HTMLElement } */) => {
event.preventDefault();
const { section } = event.currentTarget.dataset;
this.setState({ section });
@@ -68,7 +72,7 @@ export default class GlobalHelp extends React.PureComponent {
}
};

renderMenuItem = (section: string) =>
renderMenuItem = (section /*: string */) =>
<li key={section}>
<a
className={classNames({ active: section === this.state.section })}

+ 3
- 1
server/sonar-web/src/main/js/app/components/help/LinksHelp.js 查看文件

@@ -22,9 +22,11 @@ import React from 'react';
import { Link } from 'react-router';
import { translate } from '../../../helpers/l10n';

/*::
type Props = { onClose: () => void };
*/

export default function LinksHelp({ onClose }: Props) {
export default function LinksHelp({ onClose } /*: Props */) {
return (
<div>
<h2 className="spacer-top spacer-bottom">

+ 3
- 1
server/sonar-web/src/main/js/app/components/help/LinksHelpSonarCloud.js 查看文件

@@ -22,9 +22,11 @@ import React from 'react';
import { Link } from 'react-router';
import { translate } from '../../../helpers/l10n';

/*::
type Props = { onClose: () => void };
*/

export default function LinksHelpSonarCloud({ onClose }: Props) {
export default function LinksHelpSonarCloud({ onClose } /*: Props */) {
return (
<div>
<h2 className="spacer-top spacer-bottom">

+ 4
- 2
server/sonar-web/src/main/js/app/components/help/TutorialsHelp.js 查看文件

@@ -21,10 +21,12 @@
import React from 'react';
import { translate } from '../../../helpers/l10n';

/*::
type Props = { onTutorialSelect: () => void };
*/

export default function TutorialsHelp({ onTutorialSelect }: Props) {
const handleClick = (event: Event) => {
export default function TutorialsHelp({ onTutorialSelect } /*: Props */) {
const handleClick = (event /*: Event */) => {
event.preventDefault();
onTutorialSelect();
};

+ 1
- 1
server/sonar-web/src/main/js/app/components/help/__tests__/GlobalHelp-test.js 查看文件

@@ -65,6 +65,6 @@ it('display special links page for SonarCloud', () => {
expect(wrapper.find('LinksHelpSonarCloud')).toHaveLength(1);
});

function clickOnSection(wrapper: Object, section: string) {
function clickOnSection(wrapper /*: Object */, section /*: string */) {
click(wrapper.find(`[data-section="${section}"]`), { currentTarget: { dataset: { section } } });
}

+ 7
- 3
server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js 查看文件

@@ -33,22 +33,26 @@ import { getCurrentUser, getAppState, getSettingValue } from '../../../../store/
import { translate } from '../../../../helpers/l10n';
import './GlobalNav.css';

/*::
type Props = {
appState: { organizationsEnabled: boolean },
currentUser: { isLoggedIn: boolean, showOnboardingTutorial: true },
sonarCloud: boolean
};
*/

/*::
type State = {
helpOpen: boolean,
onboardingTutorialOpen: boolean,
onboardingTutorialTooltip: boolean
};
*/

class GlobalNav extends React.PureComponent {
interval: ?number;
props: Props;
state: State = {
/*:: interval: ?number; */
/*:: props: Props; */
state /*: State */ = {
helpOpen: false,
onboardingTutorialOpen: false,
onboardingTutorialTooltip: false

+ 13
- 7
server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js 查看文件

@@ -26,12 +26,15 @@ import Avatar from '../../../../components/ui/Avatar';
import OrganizationLink from '../../../../components/ui/OrganizationLink';
import { translate } from '../../../../helpers/l10n';

/*::
type CurrentUser = {
email?: string,
isLoggedIn: boolean,
name: string
};
*/

/*::
type Props = {
appState: {
organizationsEnabled: boolean
@@ -42,27 +45,30 @@ type Props = {
organizations: Array<{ key: string, name: string }>,
router: { push: string => void }
};
*/

/*::
type State = {
open: boolean
};
*/

export default class GlobalNavUser extends React.PureComponent {
node: HTMLElement;
props: Props;
state: State = { open: false };
/*:: node: HTMLElement; */
/*:: props: Props; */
state /*: State */ = { open: false };

componentWillUnmount() {
window.removeEventListener('click', this.handleClickOutside);
}

handleClickOutside = (event: { target: HTMLElement }) => {
handleClickOutside = (event /*: { target: HTMLElement } */) => {
if (!this.node || !this.node.contains(event.target)) {
this.closeDropdown();
}
};

handleLogin = (e: Event) => {
handleLogin = (e /*: Event */) => {
e.preventDefault();
const shouldReturnToCurrentPage = window.location.pathname !== `${window.baseUrl}/about`;
if (shouldReturnToCurrentPage) {
@@ -74,13 +80,13 @@ export default class GlobalNavUser extends React.PureComponent {
}
};

handleLogout = (e: Event) => {
handleLogout = (e /*: Event */) => {
e.preventDefault();
this.closeDropdown();
this.props.router.push('/sessions/logout');
};

toggleDropdown = (evt: Event) => {
toggleDropdown = (evt /*: Event */) => {
evt.preventDefault();
if (this.state.open) {
this.closeDropdown();

+ 27
- 22
server/sonar-web/src/main/js/app/components/search/Search.js 查看文件

@@ -26,7 +26,7 @@ import { debounce, keyBy, uniqBy } from 'lodash';
import SearchResults from './SearchResults';
import SearchResult from './SearchResult';
import { sortQualifiers } from './utils';
import type { Component, More, Results } from './utils';
/*:: import type { Component, More, Results } from './utils'; */
import RecentHistory from '../../components/RecentHistory';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import ClockIcon from '../../../components/common/ClockIcon';
@@ -36,11 +36,14 @@ import { scrollToElement } from '../../../helpers/scrolling';
import { getProjectUrl } from '../../../helpers/urls';
import './Search.css';

/*::
type Props = {|
appState: { organizationsEnabled: boolean },
currentUser: { isLoggedIn: boolean }
|};
*/

/*::
type State = {
loading: boolean,
loadingMore: ?string,
@@ -53,20 +56,22 @@ type State = {
selected: ?string,
shortQuery: boolean
};
*/

export default class Search extends React.PureComponent {
input: HTMLElement;
mounted: boolean;
node: HTMLElement;
nodes: { [string]: HTMLElement };
props: Props;
state: State;
/*:: input: HTMLElement; */
/*:: mounted: boolean; */
/*:: node: HTMLElement; */
/*:: nodes: { [string]: HTMLElement };
*/
/*:: props: Props; */
/*:: state: State; */

static contextTypes = {
router: PropTypes.object
};

constructor(props: Props) {
constructor(props /*: Props */) {
super(props);
this.nodes = {};
this.search = debounce(this.search, 250);
@@ -97,7 +102,7 @@ export default class Search extends React.PureComponent {
this.nodes = {};
}

componentDidUpdate(prevProps: Props, prevState: State) {
componentDidUpdate(prevProps /*: Props */, prevState /*: State */) {
if (prevState.selected !== this.state.selected) {
this.scrollToSelected();
}
@@ -109,7 +114,7 @@ export default class Search extends React.PureComponent {
window.removeEventListener('click', this.handleClickOutside);
}

handleClickOutside = (event: { target: HTMLElement }) => {
handleClickOutside = (event /*: { target: HTMLElement } */) => {
if (!this.node || !this.node.contains(event.target)) {
this.closeSearch(false);
}
@@ -123,7 +128,7 @@ export default class Search extends React.PureComponent {
this.setState({ open: true });
};

closeSearch = (clear: boolean = true) => {
closeSearch = (clear /*: boolean */ = true) => {
if (this.input) {
this.input.blur();
}
@@ -146,7 +151,7 @@ export default class Search extends React.PureComponent {
);
};

getPlainComponentsList = (results: Results, more: More): Array<string> =>
getPlainComponentsList = (results /*: Results */, more /*: More */) =>
sortQualifiers(Object.keys(results)).reduce((components, qualifier) => {
const next = [...components, ...results[qualifier].map(component => component.key)];
if (more[qualifier]) {
@@ -155,7 +160,7 @@ export default class Search extends React.PureComponent {
return next;
}, []);

mergeWithRecentlyBrowsed = (components: Array<Component>) => {
mergeWithRecentlyBrowsed = (components /*: Array<Component> */) => {
const recentlyBrowsed = RecentHistory.get().map(component => ({
...component,
isRecentlyBrowsed: true,
@@ -164,7 +169,7 @@ export default class Search extends React.PureComponent {
return uniqBy([...components, ...recentlyBrowsed], 'key');
};

search = (query: string) => {
search = (query /*: string */) => {
if (query.length === 0 || query.length >= 2) {
this.setState({ loading: true });
const recentlyBrowsed = RecentHistory.get().map(component => component.key);
@@ -195,7 +200,7 @@ export default class Search extends React.PureComponent {
}
};

searchMore = (qualifier: string) => {
searchMore = (qualifier /*: string */) => {
if (this.state.query.length !== 1) {
this.setState({ loading: true, loadingMore: qualifier });
const recentlyBrowsed = RecentHistory.get().map(component => component.key);
@@ -220,14 +225,14 @@ export default class Search extends React.PureComponent {
}
};

handleQueryChange = (event: { currentTarget: HTMLInputElement }) => {
handleQueryChange = (event /*: { currentTarget: HTMLInputElement } */) => {
const query = event.currentTarget.value;
this.setState({ query, shortQuery: query.length === 1 });
this.search(query);
};

selectPrevious = () => {
this.setState(({ more, results, selected }: State) => {
this.setState(({ more, results, selected } /*: State */) => {
if (selected) {
const list = this.getPlainComponentsList(results, more);
const index = list.indexOf(selected);
@@ -237,7 +242,7 @@ export default class Search extends React.PureComponent {
};

selectNext = () => {
this.setState(({ more, results, selected }: State) => {
this.setState(({ more, results, selected } /*: State */) => {
if (selected) {
const list = this.getPlainComponentsList(results, more);
const index = list.indexOf(selected);
@@ -267,7 +272,7 @@ export default class Search extends React.PureComponent {
}
};

handleKeyDown = (event: KeyboardEvent) => {
handleKeyDown = (event /*: KeyboardEvent */) => {
switch (event.keyCode) {
case 13:
event.preventDefault();
@@ -288,15 +293,15 @@ export default class Search extends React.PureComponent {
}
};

handleSelect = (selected: string) => {
handleSelect = (selected /*: string */) => {
this.setState({ selected });
};

innerRef = (component: string, node: HTMLElement) => {
innerRef = (component /*: string */, node /*: HTMLElement */) => {
this.nodes[component] = node;
};

renderResult = (component: Component) =>
renderResult = (component /*: Component */) =>
<SearchResult
appState={this.props.appState}
component={component}

+ 11
- 7
server/sonar-web/src/main/js/app/components/search/SearchResult.js 查看文件

@@ -20,13 +20,14 @@
// @flow
import React from 'react';
import { Link } from 'react-router';
import type { Component } from './utils';
/*:: import type { Component } from './utils'; */
import FavoriteIcon from '../../../components/common/FavoriteIcon';
import QualifierIcon from '../../../components/shared/QualifierIcon';
import ClockIcon from '../../../components/common/ClockIcon';
import Tooltip from '../../../components/controls/Tooltip';
import { getProjectUrl } from '../../../helpers/urls';

/*::
type Props = {|
appState: { organizationsEnabled: boolean },
component: Component,
@@ -37,17 +38,20 @@ type Props = {|
projects: { [string]: { name: string } },
selected: boolean
|};
*/

/*::
type State = {
tooltipVisible: boolean
};
*/

const TOOLTIP_DELAY = 1000;

export default class SearchResult extends React.PureComponent {
interval: ?number;
props: Props;
state: State = { tooltipVisible: false };
/*:: interval: ?number; */
/*:: props: Props; */
state /*: State */ = { tooltipVisible: false };

componentDidMount() {
if (this.props.selected) {
@@ -55,7 +59,7 @@ export default class SearchResult extends React.PureComponent {
}
}

componentWillReceiveProps(nextProps: Props) {
componentWillReceiveProps(nextProps /*: Props */) {
if (!this.props.selected && nextProps.selected) {
this.scheduleTooltip();
} else if (this.props.selected && !nextProps.selected) {
@@ -82,7 +86,7 @@ export default class SearchResult extends React.PureComponent {
this.props.onSelect(this.props.component.key);
};

renderOrganization = (component: Component) => {
renderOrganization = (component /*: Component */) => {
if (!this.props.appState.organizationsEnabled) {
return null;
}
@@ -102,7 +106,7 @@ export default class SearchResult extends React.PureComponent {
: null;
};

renderProject = (component: Component) => {
renderProject = (component /*: Component */) => {
if (!['BRC', 'FIL', 'UTS'].includes(component.qualifier) || component.project == null) {
return null;
}

+ 4
- 2
server/sonar-web/src/main/js/app/components/search/SearchResults.js 查看文件

@@ -21,9 +21,10 @@
import React from 'react';
import SearchShowMore from './SearchShowMore';
import { sortQualifiers } from './utils';
import type { Component, More, Results } from './utils';
/*:: import type { Component, More, Results } from './utils'; */
import { translate } from '../../../helpers/l10n';

/*::
type Props = {|
allowMore: boolean,
loadingMore: ?string,
@@ -35,9 +36,10 @@ type Props = {|
results: Results,
selected: ?string
|};
*/

export default class SearchResults extends React.PureComponent {
props: Props;
/*:: props: Props; */

render() {
const qualifiers = Object.keys(this.props.results);

+ 5
- 3
server/sonar-web/src/main/js/app/components/search/SearchShowMore.js 查看文件

@@ -23,6 +23,7 @@ import classNames from 'classnames';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';

/*::
type Props = {|
allowMore: boolean,
loadingMore: ?string,
@@ -31,11 +32,12 @@ type Props = {|
qualifier: string,
selected: boolean
|};
*/

export default class SearchShowMore extends React.PureComponent {
props: Props;
/*:: props: Props; */

handleMoreClick = (event: MouseEvent & { currentTarget: HTMLElement }) => {
handleMoreClick = (event /*: MouseEvent & { currentTarget: HTMLElement } */) => {
event.preventDefault();
event.stopPropagation();
event.currentTarget.blur();
@@ -43,7 +45,7 @@ export default class SearchShowMore extends React.PureComponent {
this.props.onMoreClick(qualifier);
};

handleMoreMouseEnter = (event: { currentTarget: HTMLElement }) => {
handleMoreMouseEnter = (event /*: { currentTarget: HTMLElement } */) => {
const { qualifier } = event.currentTarget.dataset;
this.props.onSelect(`qualifier###${qualifier}`);
};

+ 6
- 6
server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.js 查看文件

@@ -19,11 +19,11 @@
*/
import React from 'react';
import { shallow, mount } from 'enzyme';
import type { ShallowWrapper } from 'enzyme';
/*:: import type { ShallowWrapper } from 'enzyme'; */
import Search from '../Search';
import { elementKeydown, clickOutside } from '../../../../helpers/testUtils';

function render(props?: Object) {
function render(props /*: ?Object */) {
return shallow(
<Search
appState={{ organizationsEnabled: false }}
@@ -33,21 +33,21 @@ function render(props?: Object) {
);
}

function component(key: string, qualifier: string = 'TRK') {
function component(key /*: string */, qualifier /*: string */ = 'TRK') {
return { key, name: key, qualifier };
}

function next(form: ShallowWrapper, expected: string) {
function next(form /*: ShallowWrapper */, expected /*: string */) {
elementKeydown(form.find('input'), 40);
expect(form.state().selected).toBe(expected);
}

function prev(form: ShallowWrapper, expected: string) {
function prev(form /*: ShallowWrapper */, expected /*: string */) {
elementKeydown(form.find('input'), 38);
expect(form.state().selected).toBe(expected);
}

function select(form: ShallowWrapper, expected: string) {
function select(form /*: ShallowWrapper */, expected /*: string */) {
form.instance().handleSelect(expected);
expect(form.state().selected).toBe(expected);
}

+ 1
- 1
server/sonar-web/src/main/js/app/components/search/__tests__/SearchResult-test.js 查看文件

@@ -22,7 +22,7 @@ import React from 'react';
import { shallow } from 'enzyme';
import SearchResult from '../SearchResult';

function render(props?: Object) {
function render(props /*: ?Object */) {
return shallow(
// $FlowFixMe
<SearchResult

+ 1
- 1
server/sonar-web/src/main/js/app/components/search/__tests__/SearchResults-test.js 查看文件

@@ -71,6 +71,6 @@ it('renders "Show More" link', () => {
).toMatchSnapshot();
});

function component(key: string, qualifier: string = 'TRK') {
function component(key /*: string */, qualifier /*: string */ = 'TRK') {
return { key, name: key, qualifier };
}

+ 7
- 1
server/sonar-web/src/main/js/app/components/search/utils.js 查看文件

@@ -22,10 +22,11 @@ import { sortBy } from 'lodash';

const ORDER = ['DEV', 'VW', 'SVW', 'APP', 'TRK', 'BRC', 'FIL', 'UTS'];

export function sortQualifiers(qualifiers: Array<string>) {
export function sortQualifiers(qualifiers /*: Array<string> */) {
return sortBy(qualifiers, qualifier => ORDER.indexOf(qualifier));
}

/*::
export type Component = {
isFavorite?: boolean,
isRecentlyBrowsed?: boolean,
@@ -36,7 +37,12 @@ export type Component = {
project?: string,
qualifier: string
};
*/

/*::
export type Results = { [qualifier: string]: Array<Component> };
*/

/*::
export type More = { [string]: number };
*/

+ 2
- 2
server/sonar-web/src/main/js/app/utils/installExtensionsHandler.js 查看文件

@@ -20,7 +20,7 @@
// @flow
const extensions = {};

const registerExtension = (key: string, start: Function) => {
const registerExtension = (key /*: string */, start /*: Function */) => {
extensions[key] = start;
};

@@ -28,6 +28,6 @@ export default () => {
window.registerExtension = registerExtension;
};

export const getExtensionFromCache = (key: string) => {
export const getExtensionFromCache = (key /*: string */) => {
return extensions[key];
};

+ 1
- 1
server/sonar-web/src/main/js/app/utils/throwGlobalError.js 查看文件

@@ -21,7 +21,7 @@
import getStore from './getStore';
import { onFail } from '../../store/rootActions';

export default function throwGlobalError(error: Object) {
export default function throwGlobalError(error /*: Object */) {
const store = getStore();
onFail(store.dispatch)(error);
return Promise.reject();

+ 1
- 2
server/sonar-web/src/main/js/apps/about/actions.js 查看文件

@@ -17,11 +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.
*/
// @flow
import { getValues } from '../../api/settings';
import { receiveValues } from '../settings/store/values/actions';

export const fetchAboutPageSettings = (): Function => (dispatch: Function): Promise<*> => {
export const fetchAboutPageSettings = () => dispatch => {
const keys = ['sonar.lf.aboutText'];

return getValues(keys.join()).then(values => {

+ 6
- 3
server/sonar-web/src/main/js/apps/about/components/AboutApp.js 查看文件

@@ -39,6 +39,7 @@ import { fetchAboutPageSettings } from '../actions';
import AboutAppForSonarQubeDotComLazyLoader from './AboutAppForSonarQubeDotComLazyLoader';
import '../styles.css';

/*::
type State = {
loading: boolean,
projectsCount: number,
@@ -48,11 +49,12 @@ type State = {
}
}
};
*/

class AboutApp extends React.PureComponent {
mounted: boolean;
/*:: mounted: boolean; */

props: {
/*:: props: {
appState: {
defaultOrganization: string,
organizationsEnabled: boolean
@@ -62,8 +64,9 @@ class AboutApp extends React.PureComponent {
fetchAboutPageSettings: () => Promise<*>,
sonarqubeDotCom?: { value: string }
};
*/

state: State = {
state /*: State */ = {
loading: true,
projectsCount: 0
};

+ 3
- 1
server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js 查看文件

@@ -31,6 +31,7 @@ import AboutScanners from './AboutScanners';
import SonarCloudGetStarted from './SonarCloudGetStarted';
import '../sonarqube-dot-com-styles.css';

/*::
type Props = {
appState: {
defaultOrganization: string,
@@ -44,8 +45,9 @@ type Props = {
projectsCount: number,
vulnerabilities: number
};
*/

export default function AboutAppForSonarQubeDotCom(props: Props) {
export default function AboutAppForSonarQubeDotCom(props /*: Props */) {
const { customText } = props;

return (

+ 3
- 1
server/sonar-web/src/main/js/apps/about/components/AboutProjects.js 查看文件

@@ -23,12 +23,14 @@ import { Link } from 'react-router';
import { formatMeasure } from '../../../helpers/measures';
import { translate } from '../../../helpers/l10n';

/*::
type Props = {
count: number,
loading: boolean
};
*/

export default function AboutProjects({ count, loading }: Props) {
export default function AboutProjects({ count, loading } /*: Props */) {
return (
<div className="about-page-projects">
{loading && <i className="spinner" />}

+ 3
- 1
server/sonar-web/src/main/js/apps/about/components/AboutRulesForSonarQubeDotCom.js 查看文件

@@ -22,14 +22,16 @@ import React from 'react';
import { Link } from 'react-router';
import { getRulesUrl } from '../../../helpers/urls';

/*::
type Props = {
appState: {
defaultOrganization: string,
organizationsEnabled: boolean
}
};
*/

export default function AboutRulesForSonarQubeDotCom(props: Props) {
export default function AboutRulesForSonarQubeDotCom(props /*: Props */) {
const organization = props.appState.defaultOrganization;

return (

+ 3
- 1
server/sonar-web/src/main/js/apps/about/components/AboutStandards.js 查看文件

@@ -29,14 +29,16 @@ const owaspTags =
'owasp-a1,owasp-a2,owasp-a3,owasp-a4,owasp-a5,owasp-a6,owasp-a7,owasp-a8,owasp-a9,owasp-a10';
const sans25Tags = 'sans-top25-porous,sans-top25-risky,sans-top25-insecure';

/*::
type Props = {
appState: {
defaultOrganization: string,
organizationsEnabled: boolean
}
};
*/

export default function AboutStandards(props: Props) {
export default function AboutStandards(props /*: Props */) {
const organization = props.appState.organizationsEnabled
? props.appState.defaultOrganization
: null;

+ 5
- 1
server/sonar-web/src/main/js/apps/about/components/EntryIssueTypes.js 查看文件

@@ -27,14 +27,18 @@ import BugIcon from '../../../components/icons-components/BugIcon';
import VulnerabilityIcon from '../../../components/icons-components/VulnerabilityIcon';
import CodeSmellIcon from '../../../components/icons-components/CodeSmellIcon';

/*::
type Props = {
bugs: ?number,
codeSmells: ?number,
loading: boolean,
vulnerabilities: ?number
};
*/

export default function EntryIssueTypes({ bugs, codeSmells, loading, vulnerabilities }: Props) {
export default function EntryIssueTypes(
{ bugs, codeSmells, loading, vulnerabilities } /*: Props */
) {
return (
<div className="about-page-projects">
{loading && <i className="spinner" />}

+ 5
- 6
server/sonar-web/src/main/js/apps/about/components/EntryIssueTypesForSonarQubeDotCom.js 查看文件

@@ -27,19 +27,18 @@ import BugIconForSonarQubeDotCom from './BugIconForSonarQubeDotCom';
import VulnerabilityIconForSonarQubeDotCom from './VulnerabilityIconForSonarQubeDotCom';
import CodeSmellIconForSonarQubeDotCom from './CodeSmellIconForSonarQubeDotCom';

/*::
type Props = {
bugs: ?number,
codeSmells: ?number,
loading: boolean,
vulnerabilities: ?number
};
*/

export default function EntryIssueTypesForSonarQubeDotCom({
bugs,
codeSmells,
loading,
vulnerabilities
}: Props) {
export default function EntryIssueTypesForSonarQubeDotCom(
{ bugs, codeSmells, loading, vulnerabilities } /*: Props */
) {
return (
<div className="about-page-projects">
{loading && <i className="spinner" />}

+ 5
- 3
server/sonar-web/src/main/js/apps/about/components/SonarCloudGetStarted.js 查看文件

@@ -22,6 +22,7 @@ import React from 'react';
import OAuthProviders from '../../sessions/components/OAuthProviders';
import { getIdentityProviders } from '../../../api/users';

/*::
type State = {
identityProviders: Array<{
backgroundColor: string,
@@ -31,10 +32,11 @@ type State = {
}>,
loading: boolean
};
*/

export default class SonarCloudGetStarted extends React.PureComponent {
mounted: boolean;
state: State = {
/*:: mounted: boolean; */
state /*: State */ = {
identityProviders: [],
loading: true
};
@@ -57,7 +59,7 @@ export default class SonarCloudGetStarted extends React.PureComponent {
});
};

formatLabel = (name: string) => `Start with ${name}`;
formatLabel = (name /*: string */) => `Start with ${name}`;

render() {
if (this.state.loading) {

+ 3
- 1
server/sonar-web/src/main/js/apps/account/components/Nav.js 查看文件

@@ -23,11 +23,13 @@ import { Link, IndexLink } from 'react-router';
import NavBarTabs from '../../../components/nav/NavBarTabs';
import { translate } from '../../../helpers/l10n';

/*::
type Props = {
customOrganizations: boolean
};
*/

export default function Nav({ customOrganizations }: Props) {
export default function Nav({ customOrganizations } /*: Props */) {
return (
<nav className="account-nav">
<NavBarTabs>

+ 5
- 3
server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js 查看文件

@@ -26,14 +26,15 @@ import {
getNotificationChannels,
getNotificationGlobalTypes
} from '../../../store/rootReducer';
import type {
/*:: import type {
Notification,
NotificationsState,
ChannelsState,
TypesState
} from '../../../store/notifications/duck';
} from '../../../store/notifications/duck'; */
import { addNotification, removeNotification } from './actions';

/*::
type Props = {
notifications: NotificationsState,
channels: ChannelsState,
@@ -41,8 +42,9 @@ type Props = {
addNotification: (n: Notification) => void,
removeNotification: (n: Notification) => void
};
*/

function GlobalNotifications(props: Props) {
function GlobalNotifications(props /*: Props */) {
return (
<section>
<h2 className="spacer-bottom">

+ 2
- 1
server/sonar-web/src/main/js/apps/account/notifications/Notifications.js 查看文件

@@ -27,9 +27,10 @@ import { translate } from '../../../helpers/l10n';
import { fetchNotifications } from './actions';

class Notifications extends React.PureComponent {
props: {
/*:: props: {
fetchNotifications: () => void
};
*/

componentDidMount() {
this.props.fetchNotifications();

+ 6
- 5
server/sonar-web/src/main/js/apps/account/notifications/NotificationsList.js 查看文件

@@ -20,15 +20,15 @@
import React from 'react';
import Checkbox from '../../../components/controls/Checkbox';
import { translate } from '../../../helpers/l10n';
import {
/*:: import type {
Notification,
NotificationsState,
ChannelsState,
TypesState
} from '../../../store/notifications/duck';
} from '../../../store/notifications/duck'; */

export default class NotificationsList extends React.PureComponent {
props: {
/*:: props: {
onAdd: (n: Notification) => void,
onRemove: (n: Notification) => void,
channels: ChannelsState,
@@ -36,14 +36,15 @@ export default class NotificationsList extends React.PureComponent {
types: TypesState,
notifications: NotificationsState
};
*/

isEnabled(type: string, channel: string): boolean {
isEnabled(type /*: string */, channel /*: string */) /*: boolean */ {
return !!this.props.notifications.find(
notification => notification.type === type && notification.channel === channel
);
}

handleCheck(type: string, channel: string, checked: boolean) {
handleCheck(type /*: string */, channel /*: string */, checked /*: boolean */) {
if (checked) {
this.props.onAdd({ type, channel });
} else {

+ 4
- 3
server/sonar-web/src/main/js/apps/account/notifications/ProjectNotifications.js 查看文件

@@ -28,17 +28,17 @@ import {
getNotificationChannels,
getNotificationPerProjectTypes
} from '../../../store/rootReducer';
import type {
/*:: import type {
Notification,
NotificationsState,
ChannelsState,
TypesState
} from '../../../store/notifications/duck';
} from '../../../store/notifications/duck'; */
import { addNotification, removeNotification } from './actions';
import { getProjectUrl } from '../../../helpers/urls';

class ProjectNotifications extends React.PureComponent {
props: {
/*:: props: {
project: {
key: string,
name: string,
@@ -50,6 +50,7 @@ class ProjectNotifications extends React.PureComponent {
addNotification: (n: Notification) => void,
removeNotification: (n: Notification) => void
};
*/

handleAddNotification({ channel, type }) {
this.props.addNotification({

+ 7
- 3
server/sonar-web/src/main/js/apps/account/notifications/Projects.js 查看文件

@@ -27,28 +27,32 @@ import { translate } from '../../../helpers/l10n';
import { getSuggestions } from '../../../api/components';
import { getProjectsWithNotifications } from '../../../store/rootReducer';

/*::
type Props = {
projects: Array<{
key: string,
name: string
}>
};
*/

/*::
type State = {
addedProjects: Array<{
key: string,
name: string
}>
};
*/

class Projects extends React.PureComponent {
props: Props;
/*:: props: Props; */

state: State = {
state /*: State */ = {
addedProjects: []
};

componentWillReceiveProps(nextProps: Props) {
componentWillReceiveProps(nextProps /*: Props */) {
// remove all projects from `this.state.addedProjects`
// that already exist in `nextProps.projects`
const nextAddedProjects = differenceBy(

+ 6
- 6
server/sonar-web/src/main/js/apps/account/notifications/actions.js 查看文件

@@ -19,17 +19,17 @@
*/
// @flow
import * as api from '../../../api/notifications';
import type { GetNotificationsResponse } from '../../../api/notifications';
/*:: import type { GetNotificationsResponse } from '../../../api/notifications'; */
import { onFail, fetchOrganizations } from '../../../store/rootActions';
import {
receiveNotifications,
addNotification as addNotificationAction,
removeNotification as removeNotificationAction
} from '../../../store/notifications/duck';
import type { Notification } from '../../../store/notifications/duck';
/*:: import type { Notification } from '../../../store/notifications/duck'; */

export const fetchNotifications = () => (dispatch: Function) => {
const onFulfil = (response: GetNotificationsResponse) => {
export const fetchNotifications = () => (dispatch /*: Function */) => {
const onFulfil = (response /*: GetNotificationsResponse */) => {
const organizations = response.notifications
.filter(n => n.organization)
.map(n => n.organization);
@@ -49,12 +49,12 @@ export const fetchNotifications = () => (dispatch: Function) => {
return api.getNotifications().then(onFulfil, onFail(dispatch));
};

export const addNotification = (n: Notification) => (dispatch: Function) =>
export const addNotification = (n /*: Notification */) => (dispatch /*: Function */) =>
api
.addNotification(n.channel, n.type, n.project)
.then(() => dispatch(addNotificationAction(n)), onFail(dispatch));

export const removeNotification = (n: Notification) => (dispatch: Function) =>
export const removeNotification = (n /*: Notification */) => (dispatch /*: Function */) =>
api
.removeNotification(n.channel, n.type, n.project)
.then(() => dispatch(removeNotificationAction(n)), onFail(dispatch));

+ 10
- 7
server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.js 查看文件

@@ -26,6 +26,7 @@ import { withRouter } from 'react-router';
import { translate } from '../../../helpers/l10n';
import { createOrganization } from '../../organizations/actions';

/*::
type State = {
loading: boolean,
avatar: string,
@@ -35,14 +36,16 @@ type State = {
name: string,
url: string
};
*/

class CreateOrganizationForm extends React.PureComponent {
mounted: boolean;
state: State;
props: {
/*:: mounted: boolean; */
/*:: state: State; */
/*:: props: {
createOrganization: (fields: {}) => Promise<*>,
router: { push: string => void }
};
*/

constructor(props) {
super(props);
@@ -83,19 +86,19 @@ class CreateOrganizationForm extends React.PureComponent {
this.closeForm();
};

handleAvatarInputChange = (e: Object) => {
handleAvatarInputChange = (e /*: Object */) => {
const { value } = e.target;
this.setState({ avatar: value });
this.changeAvatarImage(value);
};

changeAvatarImage = (value: string) => {
changeAvatarImage = (value /*: string */) => {
this.setState({ avatarImage: value });
};

handleSubmit = (e: Object) => {
handleSubmit = (e /*: Object */) => {
e.preventDefault();
const organization: Object = { name: this.state.name };
const organization /*: Object */ = { name: this.state.name };
if (this.state.avatar) {
Object.assign(organization, { avatar: this.state.avatar });
}

+ 4
- 2
server/sonar-web/src/main/js/apps/account/organizations/OrganizationCard.js 查看文件

@@ -20,13 +20,15 @@
// @flow
import React from 'react';
import OrganizationLink from '../../../components/ui/OrganizationLink';
import type { Organization } from '../../../store/organizations/duck';
/*:: import type { Organization } from '../../../store/organizations/duck'; */

/*::
type Props = {
organization: Organization
};
*/

export default function OrganizationCard(props: Props) {
export default function OrganizationCard(props /*: Props */) {
const { organization } = props;

return (

+ 4
- 2
server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.js 查看文件

@@ -21,13 +21,15 @@
import React from 'react';
import { sortBy } from 'lodash';
import OrganizationCard from './OrganizationCard';
import type { Organization } from '../../../store/organizations/duck';
/*:: import type { Organization } from '../../../store/organizations/duck'; */

/*::
type Props = {
organizations: Array<Organization>
};
*/

export default function OrganizationsList(props: Props) {
export default function OrganizationsList(props /*: Props */) {
return (
<ul className="account-projects-list">
{sortBy(props.organizations, organization =>

+ 5
- 4
server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.js 查看文件

@@ -26,12 +26,12 @@ import OrganizationsList from './OrganizationsList';
import { translate } from '../../../helpers/l10n';
import { fetchIfAnyoneCanCreateOrganizations, fetchMyOrganizations } from './actions';
import { getAppState, getMyOrganizations, getSettingValue } from '../../../store/rootReducer';
import type { Organization } from '../../../store/organizations/duck';
/*:: import type { Organization } from '../../../store/organizations/duck'; */

class UserOrganizations extends React.PureComponent {
mounted: boolean;
/*:: mounted: boolean; */

props: {
/*:: props: {
anyoneCanCreate?: { value: string },
canAdmin: boolean,
children?: React.Element<*>,
@@ -39,8 +39,9 @@ class UserOrganizations extends React.PureComponent {
fetchIfAnyoneCanCreateOrganizations: () => Promise<*>,
fetchMyOrganizations: () => Promise<*>
};
*/

state: { loading: boolean } = {
state /*: { loading: boolean } */ = {
loading: true
};


+ 2
- 5
server/sonar-web/src/main/js/apps/account/organizations/actions.js 查看文件

@@ -17,13 +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.
*/
// @flow
import * as api from '../../../api/organizations';
import { receiveMyOrganizations } from '../../../store/organizations/duck';
import { getValues } from '../../../api/settings';
import { receiveValues } from '../../settings/store/values/actions';

export const fetchMyOrganizations = (): Function => (dispatch: Function): Promise<*> => {
export const fetchMyOrganizations = () => dispatch => {
return api.getMyOrganizations().then(keys => {
if (keys.length > 0) {
return api.getOrganizations(keys).then(({ organizations }) => {
@@ -35,9 +34,7 @@ export const fetchMyOrganizations = (): Function => (dispatch: Function): Promis
});
};

export const fetchIfAnyoneCanCreateOrganizations = (): Function => (
dispatch: Function
): Promise<*> => {
export const fetchIfAnyoneCanCreateOrganizations = () => dispatch => {
return getValues('sonar.organizations.anyoneCanCreate').then(values => {
dispatch(receiveValues(values));
});

+ 3
- 1
server/sonar-web/src/main/js/apps/account/profile/Profile.js 查看文件

@@ -25,6 +25,7 @@ import UserGroups from './UserGroups';
import UserScmAccounts from './UserScmAccounts';
import { getCurrentUser, areThereCustomOrganizations } from '../../../store/rootReducer';

/*::
type Props = {
customOrganizations: boolean,
user: {
@@ -36,8 +37,9 @@ type Props = {
scmAccounts: Array<*>
}
};
*/

function Profile(props: Props) {
function Profile(props /*: Props */) {
const { customOrganizations, user } = props;

return (

+ 14
- 10
server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js 查看文件

@@ -37,18 +37,21 @@ import {
cancelTask as cancelTaskAPI
} from '../../../api/ce';
import { updateTask, mapFiltersToParameters } from '../utils';
import { Task } from '../types';
/*:: import type { Task } from '../types'; */
import { getComponent } from '../../../store/rootReducer';
import '../background-tasks.css';
import { fetchOrganizations } from '../../../store/rootActions';
import { translate } from '../../../helpers/l10n';

/*::
type Props = {
component: Object,
location: Object,
fetchOrganizations: (Array<string>) => string
};
*/

/*::
type State = {
loading: boolean,
tasks: Array<*>,
@@ -57,17 +60,18 @@ type State = {
pendingCount: number,
failingCount: number
};
*/

class BackgroundTasksApp extends React.PureComponent {
loadTasksDebounced: Function;
mounted: boolean;
props: Props;
/*:: loadTasksDebounced: Function; */
/*:: mounted: boolean; */
/*:: props: Props; */

static contextTypes = {
router: PropTypes.object.isRequired
};

state: State = {
state /*: State */ = {
loading: true,
tasks: [],

@@ -92,7 +96,7 @@ class BackgroundTasksApp extends React.PureComponent {
});
}

componentDidUpdate(prevProps: Props) {
componentDidUpdate(prevProps /*: Props */) {
if (
prevProps.component !== this.props.component ||
prevProps.location !== this.props.location
@@ -117,7 +121,7 @@ class BackgroundTasksApp extends React.PureComponent {
const query = this.props.location.query.query || DEFAULT_FILTERS.query;

const filters = { status, taskType, currents, minSubmittedAt, maxExecutedAt, query };
const parameters: Object = mapFiltersToParameters(filters);
const parameters /*: Object */ = mapFiltersToParameters(filters);

if (this.props.component) {
parameters.componentId = this.props.component.id;
@@ -144,7 +148,7 @@ class BackgroundTasksApp extends React.PureComponent {
});
}

handleFilterUpdate(nextState: Object) {
handleFilterUpdate(nextState /*: Object */) {
const nextQuery = { ...this.props.location.query, ...nextState };

// remove defaults
@@ -160,7 +164,7 @@ class BackgroundTasksApp extends React.PureComponent {
});
}

handleCancelTask(task: Task) {
handleCancelTask(task /*: Task */) {
this.setState({ loading: true });

cancelTaskAPI(task.id).then(nextTask => {
@@ -171,7 +175,7 @@ class BackgroundTasksApp extends React.PureComponent {
});
}

handleFilterTask(task: Task) {
handleFilterTask(task /*: Task */) {
this.handleFilterUpdate({ query: task.componentKey });
}


+ 3
- 1
server/sonar-web/src/main/js/apps/background-tasks/components/CurrentsFilter.js 查看文件

@@ -22,7 +22,9 @@ import React from 'react';
import Checkbox from '../../../components/controls/Checkbox';
import { CURRENTS } from '../constants';

const CurrentsFilter = ({ value, onChange }: { value: ?string, onChange: string => void }) => {
const CurrentsFilter = (
{ value, onChange } /*: { value: ?string, onChange: string => void } */
) => {
function handleChange(value) {
const newValue = value ? CURRENTS.ONLY_CURRENTS : CURRENTS.ALL;
onChange(newValue);

+ 2
- 2
server/sonar-web/src/main/js/apps/background-tasks/components/Footer.js 查看文件

@@ -19,12 +19,12 @@
*/
/* @flow */
import React from 'react';
import { Task } from '../types';
/*:: import type { Task } from '../types'; */
import { translateWithParameters } from '../../../helpers/l10n';

const LIMIT = 1000;

const Footer = ({ tasks }: { tasks: Task[] }) => {
const Footer = ({ tasks } /*: { tasks: Task[] } */) => {
if (tasks.length < LIMIT) {
return null;
}

+ 3
- 1
server/sonar-web/src/main/js/apps/background-tasks/components/Header.js 查看文件

@@ -22,11 +22,13 @@ import React from 'react';
import Workers from './Workers';
import { translate } from '../../../helpers/l10n';

/*::
type Props = {
component?: Object
};
*/

export default function Header(props: Props) {
export default function Header(props /*: Props */) {
return (
<header className="page-header">
<h1 className="page-title">

+ 8
- 4
server/sonar-web/src/main/js/apps/background-tasks/components/ScannerContext.js 查看文件

@@ -23,19 +23,23 @@ import Modal from 'react-modal';
import { getTask } from '../../../api/ce';
import { translate } from '../../../helpers/l10n';

/*::
type Props = {
onClose: () => void,
task: { componentName: string, id: string, type: string }
};
*/

/*::
type State = {
scannerContext: ?string
};
*/

export default class ScannerContext extends React.PureComponent {
mounted: boolean;
props: Props;
state: State = {
/*:: mounted: boolean; */
/*:: props: Props; */
state /*: State */ = {
scannerContext: null
};

@@ -56,7 +60,7 @@ export default class ScannerContext extends React.PureComponent {
});
}

handleCloseClick = (event: Event) => {
handleCloseClick = (event /*: Event */) => {
event.preventDefault();
this.props.onClose();
};

+ 7
- 7
server/sonar-web/src/main/js/apps/background-tasks/components/Search.js 查看文件

@@ -38,32 +38,32 @@ export default class Search extends React.PureComponent {
onReload: PropTypes.func.isRequired
};

handleStatusChange(status: string) {
handleStatusChange(status /*: string */) {
this.props.onFilterUpdate({ status });
}

handleTypeChange(taskType: string) {
handleTypeChange(taskType /*: string */) {
this.props.onFilterUpdate({ taskType });
}

handleCurrentsChange(currents: string) {
handleCurrentsChange(currents /*: string */) {
this.props.onFilterUpdate({ currents });
}

handleDateChange(date: string) {
handleDateChange(date /*: string */) {
this.props.onFilterUpdate(date);
}

handleQueryChange(query: string) {
handleQueryChange(query /*: string */) {
this.props.onFilterUpdate({ query });
}

handleReload(e: Object) {
handleReload(e /*: Object */) {
e.target.blur();
this.props.onReload();
}

handleReset(e: Object) {
handleReset(e /*: Object */) {
e.preventDefault();
e.target.blur();
this.props.onFilterUpdate(DEFAULT_FILTERS);

+ 8
- 4
server/sonar-web/src/main/js/apps/background-tasks/components/Stacktrace.js 查看文件

@@ -23,20 +23,24 @@ import Modal from 'react-modal';
import { getTask } from '../../../api/ce';
import { translate } from '../../../helpers/l10n';

/*::
type Props = {
onClose: () => void,
task: { componentName: string, errorMessage: string, id: string, type: string }
};
*/

/*::
type State = {
loading: boolean,
stacktrace: ?string
};
*/

export default class Stacktrace extends React.PureComponent {
mounted: boolean;
props: Props;
state: State = {
/*:: mounted: boolean; */
/*:: props: Props; */
state /*: State */ = {
loading: true,
stacktrace: null
};
@@ -58,7 +62,7 @@ export default class Stacktrace extends React.PureComponent {
});
}

handleCloseClick = (event: Event) => {
handleCloseClick = (event /*: Event */) => {
event.preventDefault();
this.props.onClose();
};

+ 8
- 4
server/sonar-web/src/main/js/apps/background-tasks/components/Stats.js 查看文件

@@ -21,26 +21,30 @@
import React from 'react';
import { translate } from '../../../helpers/l10n';

/*::
type Props = {
failingCount: number,
pendingCount: number,
onShowFailing: () => void,
onCancelAllPending: () => void
};
*/

/*::
type State = Object;
*/

export default class Stats extends React.PureComponent {
props: Props;
state: State;
/*:: props: Props; */
/*:: state: State; */

handleCancelAllPending(e: Object) {
handleCancelAllPending(e /*: Object */) {
e.preventDefault();
e.target.blur();
this.props.onCancelAllPending();
}

handleShowFailing(e: Object) {
handleShowFailing(e /*: Object */) {
e.preventDefault();
e.target.blur();
this.props.onShowFailing();

+ 1
- 1
server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.js 查看文件

@@ -23,7 +23,7 @@ import Select from 'react-select';
import { STATUSES } from '../constants';
import { translate } from '../../../helpers/l10n';

const StatusFilter = ({ value, onChange }: { value: ?string, onChange: Function }) => {
const StatusFilter = ({ value, onChange } /*: { value: ?string, onChange: Function } */) => {
const options = [
{ value: STATUSES.ALL, label: translate('background_task.status.ALL') },
{

+ 4
- 2
server/sonar-web/src/main/js/apps/background-tasks/components/TaskComponent.js 查看文件

@@ -23,14 +23,16 @@ import { Link } from 'react-router';
import TaskType from './TaskType';
import QualifierIcon from '../../../components/shared/QualifierIcon';
import Organization from '../../../components/shared/Organization';
import { Task } from '../types';
/*:: import type { Task } from '../types'; */

/*::
type Props = {
task: Task,
types: Array<string>
};
*/

export default function TaskComponent(props: Props) {
export default function TaskComponent(props /*: Props */) {
const { task, types } = props;

if (!task.componentKey) {

+ 4
- 6
server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.js 查看文件

@@ -21,15 +21,13 @@
import moment from 'moment';
import React from 'react';

const TaskDate = ({
date,
baseDate,
format
}: {
const TaskDate = (
{ date, baseDate, format } /*: {
date: string,
baseDate: string,
format: string
}) => {
} */
) => {
const m = moment(date);
const baseM = moment(baseDate);
const diff = date && baseDate ? m.diff(baseM, 'days') : 0;

+ 2
- 2
server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.js 查看文件

@@ -20,13 +20,13 @@
/* @flow */
import moment from 'moment';
import React from 'react';
import { Task } from '../types';
/*:: import type { Task } from '../types'; */

function isAnotherDay(a, b) {
return !moment(a).isSame(moment(b), 'day');
}

const TaskDay = ({ task, prevTask }: { task: Task, prevTask: ?Task }) => {
const TaskDay = ({ task, prevTask } /*: { task: Task, prevTask: ?Task } */) => {
const shouldDisplay = !prevTask || isAnotherDay(task.submittedAt, prevTask.submittedAt);

return (

+ 2
- 2
server/sonar-web/src/main/js/apps/background-tasks/components/TaskExecutionTime.js 查看文件

@@ -20,9 +20,9 @@
/* @flow */
import React from 'react';
import { formatDuration } from '../utils';
import { Task } from '../types';
/*:: import type { Task } from '../types'; */

const TaskExecutionTime = ({ task }: { task: Task }) => {
const TaskExecutionTime = ({ task } /*: { task: Task } */) => {
return (
<td className="thin nowrap text-right">
{formatDuration(task.executionTimeMs)}

+ 2
- 2
server/sonar-web/src/main/js/apps/background-tasks/components/TaskStatus.js 查看文件

@@ -22,9 +22,9 @@ import React from 'react';
import { STATUSES } from './../constants';
import PendingIcon from '../../../components/shared/pending-icon';
import { translate } from '../../../helpers/l10n';
import { Task } from '../types';
/*:: import type { Task } from '../types'; */

const TaskStatus = ({ task }: { task: Task }) => {
const TaskStatus = ({ task } /*: { task: Task } */) => {
let inner;

switch (task.status) {

+ 2
- 2
server/sonar-web/src/main/js/apps/background-tasks/components/TaskType.js 查看文件

@@ -19,10 +19,10 @@
*/
/* @flow */
import React from 'react';
import { Task } from '../types';
/*:: import type { Task } from '../types'; */
import { translate } from '../../../helpers/l10n';

const TaskType = ({ task }: { task: Task }) => {
const TaskType = ({ task } /*: { task: Task } */) => {
return (
<span className="note nowrap spacer-left">
{'['}

+ 6
- 2
server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js 查看文件

@@ -23,6 +23,7 @@ import classNames from 'classnames';
import Task from './Task';
import { translate } from '../../../helpers/l10n';

/*::
type Props = {
tasks: Array<*>,
component: Object,
@@ -31,12 +32,15 @@ type Props = {
onCancelTask: Function,
onFilterTask: Function
};
*/

/*::
type State = Object;
*/

export default class Tasks extends React.PureComponent {
props: Props;
state: State;
/*:: props: Props; */
/*:: state: State; */

render() {
const { tasks, component, types, loading, onCancelTask, onFilterTask } = this.props;

+ 4
- 6
server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.js 查看文件

@@ -23,15 +23,13 @@ import Select from 'react-select';
import { ALL_TYPES } from '../constants';
import { translate } from '../../../helpers/l10n';

const TypesFilter = ({
value,
onChange,
types
}: {
const TypesFilter = (
{ value, onChange, types } /*: {
value: string,
onChange: Function,
types: string[]
}) => {
} */
) => {
const options = types.map(t => {
return {
value: t,

+ 11
- 7
server/sonar-web/src/main/js/apps/background-tasks/components/Workers.js 查看文件

@@ -24,16 +24,18 @@ import Tooltip from '../../../components/controls/Tooltip';
import { getWorkers } from '../../../api/ce';
import { translate } from '../../../helpers/l10n';

/*::
type State = {
canSetWorkerCount: boolean,
formOpen: boolean,
loading: boolean,
workerCount: number
};
*/

export default class Workers extends React.PureComponent {
mounted: boolean;
state: State = {
/*:: mounted: boolean; */
state /*: State */ = {
canSetWorkerCount: false,
formOpen: false,
loading: true,
@@ -62,12 +64,12 @@ export default class Workers extends React.PureComponent {
});
};

closeForm = (newWorkerCount?: number) =>
(newWorkerCount
closeForm = (newWorkerCount /*: ?number */) =>
newWorkerCount
? this.setState({ formOpen: false, workerCount: newWorkerCount })
: this.setState({ formOpen: false }));
: this.setState({ formOpen: false });

handleChangeClick = (event: Event) => {
handleChangeClick = (event /*: Event */) => {
event.preventDefault();
this.setState({ formOpen: true });
};
@@ -87,7 +89,9 @@ export default class Workers extends React.PureComponent {

{loading
? <i className="spinner little-spacer-left" />
: <strong className="little-spacer-left">{workerCount}</strong>}
: <strong className="little-spacer-left">
{workerCount}
</strong>}

{!loading &&
(canSetWorkerCount

+ 13
- 7
server/sonar-web/src/main/js/apps/background-tasks/components/WorkersForm.js 查看文件

@@ -27,22 +27,26 @@ import { translate } from '../../../helpers/l10n';

const MAX_WORKERS = 10;

/*::
type Props = {
onClose: (newWorkerCount?: number) => void,
workerCount: number
};
*/

/*::
type State = {
newWorkerCount: number,
submitting: boolean
};
*/

export default class WorkersForm extends React.PureComponent {
mounted: boolean;
props: Props;
state: State;
/*:: mounted: boolean; */
/*:: props: Props; */
/*:: state: State; */

constructor(props: Props) {
constructor(props /*: Props */) {
super(props);
this.state = {
newWorkerCount: props.workerCount,
@@ -60,10 +64,10 @@ export default class WorkersForm extends React.PureComponent {

handleClose = () => this.props.onClose();

handleWorkerCountChange = (option: { value: number }) =>
handleWorkerCountChange = (option /*: { value: number } */) =>
this.setState({ newWorkerCount: option.value });

handleSubmit = (event: Event) => {
handleSubmit = (event /*: Event */) => {
event.preventDefault();
this.setState({ submitting: true });
const { newWorkerCount } = this.state;
@@ -92,7 +96,9 @@ export default class WorkersForm extends React.PureComponent {
overlayClassName="modal-overlay"
onRequestClose={this.handleClose}>
<header className="modal-head">
<h2>{translate('background_tasks.change_number_of_workers')}</h2>
<h2>
{translate('background_tasks.change_number_of_workers')}
</h2>
</header>
<form onSubmit={this.handleSubmit}>
<div className="modal-body">

+ 2
- 0
server/sonar-web/src/main/js/apps/background-tasks/types.js 查看文件

@@ -17,7 +17,9 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*::
export type Task = {
incremental: boolean,
id: string
};
*/

+ 4
- 4
server/sonar-web/src/main/js/apps/background-tasks/utils.js 查看文件

@@ -19,13 +19,13 @@
*/
/* @flow */
import { STATUSES, ALL_TYPES, CURRENTS } from './constants';
import { Task } from './types';
/*:: import type { Task } from './types'; */

export function updateTask(tasks: Task[], newTask: Task) {
export function updateTask(tasks /*: Task[] */, newTask /*: Task */) {
return tasks.map(task => (task.id === newTask.id ? newTask : task));
}

export function mapFiltersToParameters(filters: Object = {}) {
export function mapFiltersToParameters(filters /*: Object */ = {}) {
const parameters = {};

if (filters.status === STATUSES.ALL) {
@@ -81,7 +81,7 @@ function format(int, suffix) {
return `${int}${suffix}`;
}

export function formatDuration(value: ?number) {
export function formatDuration(value /*: ?number */) {
if (!value) {
return '';
}

+ 3
- 2
server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js 查看文件

@@ -27,8 +27,8 @@ import { translate } from '../../../helpers/l10n';
import init from '../init';

class CodingRulesAppContainer extends React.PureComponent {
stop: ?() => void;
props: {
/*:: stop: ?() => void; */
/*:: props: {
appState: {
defaultOrganization: string,
organizationsEnabled: boolean
@@ -40,6 +40,7 @@ class CodingRulesAppContainer extends React.PureComponent {
replace: string => void
}
};
*/

componentDidMount() {
if (this.props.appState.organizationsEnabled && !this.props.params.organizationKey) {

+ 9
- 3
server/sonar-web/src/main/js/apps/coding-rules/init.js 查看文件

@@ -36,11 +36,13 @@ import { areThereCustomOrganizations } from '../../store/organizations/utils';

const App = new Marionette.Application();

App.on('start', function(options: {
App.on('start', function(
options /*: {
el: HTMLElement,
organization: ?string,
isDefaultOrganization: boolean
}) {
} */
) {
App.organization = options.organization;
const data = options.organization ? { organization: options.organization } : {};
$.get(window.baseUrl + '/api/rules/app', data)
@@ -110,7 +112,11 @@ App.on('start', function(options: {
});
});

export default function(el: HTMLElement, organization: ?string, isDefaultOrganization: boolean) {
export default function(
el /*: HTMLElement */,
organization /*: ?string */,
isDefaultOrganization /*: boolean */
) {
App.start({ el, organization, isDefaultOrganization });

return () => {

+ 15
- 15
server/sonar-web/src/main/js/apps/component-measures/components/App.js 查看文件

@@ -26,13 +26,13 @@ import MeasureOverviewContainer from './MeasureOverviewContainer';
import Sidebar from '../sidebar/Sidebar';
import { hasBubbleChart, parseQuery, serializeQuery } from '../utils';
import { translate } from '../../../helpers/l10n';
import type { Component, Query, Period } from '../types';
import type { RawQuery } from '../../../helpers/query';
import type { Metric } from '../../../store/metrics/actions';
import type { MeasureEnhanced } from '../../../components/measure/types';
/*:: import type { Component, Query, Period } from '../types'; */
/*:: import type { RawQuery } from '../../../helpers/query'; */
/*:: import type { Metric } from '../../../store/metrics/actions'; */
/*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */
import '../style.css';

type Props = {|
/*:: type Props = {|
component: Component,
currentUser: { isLoggedIn: boolean },
location: { pathname: string, query: RawQuery },
@@ -46,20 +46,20 @@ type Props = {|
router: {
push: ({ pathname: string, query?: RawQuery }) => void
}
|};
|}; */

type State = {|
/*:: type State = {|
loading: boolean,
measures: Array<MeasureEnhanced>,
leakPeriod: ?Period
|};
|}; */

export default class App extends React.PureComponent {
mounted: boolean;
props: Props;
state: State;
/*:: mounted: boolean; */
/*:: props: Props; */
/*:: state: State; */

constructor(props: Props) {
constructor(props /*: Props */) {
super(props);
this.state = {
loading: true,
@@ -79,7 +79,7 @@ export default class App extends React.PureComponent {
}
}

componentWillReceiveProps(nextProps: Props) {
componentWillReceiveProps(nextProps /*: Props */) {
if (
nextProps.component.key !== this.props.component.key ||
nextProps.metrics !== this.props.metrics
@@ -97,7 +97,7 @@ export default class App extends React.PureComponent {
}
}

fetchMeasures = ({ component, fetchMeasures, metrics, metricsKey }: Props) => {
fetchMeasures = ({ component, fetchMeasures, metrics, metricsKey } /*: Props */) => {
this.setState({ loading: true });
const filteredKeys = metricsKey.filter(
key => !metrics[key].hidden && !['DATA', 'DISTRIB'].includes(metrics[key].type)
@@ -116,7 +116,7 @@ export default class App extends React.PureComponent {
);
};

updateQuery = (newQuery: Query) => {
updateQuery = (newQuery /*: Query */) => {
const query = serializeQuery({
...parseQuery(this.props.location.query),
...newQuery

+ 7
- 7
server/sonar-web/src/main/js/apps/component-measures/components/AppContainer.js 查看文件

@@ -32,8 +32,8 @@ import { fetchMetrics } from '../../../store/rootActions';
import { getMeasuresAndMeta } from '../../../api/measures';
import { getLeakPeriod } from '../../../helpers/periods';
import { enhanceMeasure } from '../../../components/measure/utils';
import type { Component, Period } from '../types';
import type { Measure, MeasureEnhanced } from '../../../components/measure/types';
/*:: import type { Component, Period } from '../types'; */
/*:: import type { Measure, MeasureEnhanced } from '../../../components/measure/types'; */

const mapStateToProps = (state, ownProps) => ({
component: getComponent(state, ownProps.location.query.id),
@@ -42,7 +42,7 @@ const mapStateToProps = (state, ownProps) => ({
metricsKey: getMetricsKey(state)
});

const banQualityGate = (component: Component): Array<Measure> => {
function banQualityGate(component /*: Component */) /*: Array<Measure> */ {
const bannedMetrics = [];
if (!['VW', 'SVW'].includes(component.qualifier)) {
bannedMetrics.push('alert_status');
@@ -51,18 +51,18 @@ const banQualityGate = (component: Component): Array<Measure> => {
bannedMetrics.push('releasability_rating', 'releasability_effort');
}
return component.measures.filter(measure => !bannedMetrics.includes(measure.metric));
};
}

const fetchMeasures = (component: string, metricsKey: Array<string>) => (
const fetchMeasures = (component /*: string */, metricsKey /*: Array<string> */) => (
dispatch,
getState
): Promise<{ component: Component, measures: Array<MeasureEnhanced>, leakPeriod: ?Period }> => {
) => {
if (metricsKey.length <= 0) {
return Promise.resolve({ component: {}, measures: [], leakPeriod: null });
}

return getMeasuresAndMeta(component, metricsKey, { additionalFields: 'periods' }).then(r => {
const measures: Array<MeasureEnhanced> = banQualityGate(r.component).map(measure =>
const measures = banQualityGate(r.component).map(measure =>
enhanceMeasure(measure, getMetrics(getState()))
);


+ 0
- 0
server/sonar-web/src/main/js/apps/component-measures/components/Breadcrumb.js 查看文件


部分文件因文件數量過多而無法顯示

Loading…
取消
儲存