utils.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import set from 'lodash/set';
  2. import {Organization, Project} from 'app/types';
  3. export type NotificationSettingsObject = {
  4. [key: string]: {[key: string]: {[key: string]: {[key: string]: string}}};
  5. };
  6. // Which fine tuning parts are grouped by project
  7. export const isGroupedByProject = (type: string): boolean =>
  8. ['alerts', 'email', 'workflow'].includes(type);
  9. export const groupByOrganization = (projects: Project[]) => {
  10. return projects.reduce<
  11. Record<string, {organization: Organization; projects: Project[]}>
  12. >((acc, project) => {
  13. const orgSlug = project.organization.slug;
  14. if (acc.hasOwnProperty(orgSlug)) {
  15. acc[orgSlug].projects.push(project);
  16. } else {
  17. acc[orgSlug] = {
  18. organization: project.organization,
  19. projects: [project],
  20. };
  21. }
  22. return acc;
  23. }, {});
  24. };
  25. export const getFallBackValue = (notificationType: string): string => {
  26. switch (notificationType) {
  27. case 'alerts':
  28. return 'always';
  29. case 'deploy':
  30. return 'committed_only';
  31. case 'workflow':
  32. return 'subscribe_only';
  33. default:
  34. return '';
  35. }
  36. };
  37. export const providerListToString = (providers: string[]): string => {
  38. return providers.sort().join('+');
  39. };
  40. export const getChoiceString = (choices: string[][], key: string): string => {
  41. if (!choices) {
  42. return 'default';
  43. }
  44. const found = choices.find(row => row[0] === key);
  45. if (!found) {
  46. throw new Error(`Could not find ${key}`);
  47. }
  48. return found[1];
  49. };
  50. export const backfillMissingProvidersWithFallback = (
  51. data: {[key: string]: string},
  52. providerList: string[],
  53. fallbackValue: string,
  54. scopeType: string
  55. ): {[key: string]: string} => {
  56. /**
  57. * Transform `data` to include only providers expected in `providerList`.
  58. * Everything not in that list is set to "never". Missing values will be
  59. * backfilled either with a current value from `data` or `fallbackValue` if
  60. * none are present. When wiping out a provider, set the parent-independent
  61. * setting to "never" and all parent-specific settings to "default".
  62. *
  63. * For example:
  64. * f({}, ["email"], "sometimes", "user") = {"email": "sometimes"}
  65. *
  66. * f({"email": "always", pagerduty: "always"}, ["email", "slack"], "sometimes", "user) =
  67. * {"email": "always", "slack": "always", "pagerduty": "never"}
  68. */
  69. const entries: string[][] = [];
  70. let fallback = fallbackValue;
  71. for (const [provider, previousValue] of Object.entries(data)) {
  72. fallback = previousValue;
  73. let value;
  74. if (providerList.includes(provider)) {
  75. value = previousValue;
  76. } else if (scopeType === 'user') {
  77. value = 'never';
  78. } else {
  79. value = 'default';
  80. }
  81. entries.push([provider, value]);
  82. }
  83. for (const provider of providerList) {
  84. entries.push([provider, fallback]);
  85. }
  86. return Object.fromEntries(entries);
  87. };
  88. export const mergeNotificationSettings = (
  89. ...objects: NotificationSettingsObject[]
  90. ): NotificationSettingsObject => {
  91. /** Deeply merge N notification settings objects (usually just 2). */
  92. const output = {};
  93. objects.map(settingsByType =>
  94. Object.entries(settingsByType).map(([type, settingsByScopeType]) =>
  95. Object.entries(settingsByScopeType).map(([scopeType, settingsByScopeId]) =>
  96. Object.entries(settingsByScopeId).map(([scopeId, settingsByProvider]) => {
  97. set(output, [type, scopeType, scopeId].join('.'), settingsByProvider);
  98. })
  99. )
  100. )
  101. );
  102. return output;
  103. };