NotificationSource.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. Copyright (C) 2017 Cloudbase Solutions SRL
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. // @flow
  15. import moment from 'moment'
  16. import { servicesUrl } from '../constants'
  17. import Api from '../utils/ApiCaller'
  18. import type { NotificationItemData, NotificationItem } from '../types/NotificationItem'
  19. class NotificationStorage {
  20. static storeName: string = 'seenNotifications'
  21. static loadSeen(): ?NotificationItemData[] {
  22. let storage: ?string = localStorage.getItem(this.storeName)
  23. if (!storage) {
  24. return null
  25. }
  26. let notificationItems: NotificationItem[] = JSON.parse(storage)
  27. let notificationItem: ?NotificationItem = notificationItems.find(n => n.projectId === Api.projectId)
  28. if (!notificationItem) {
  29. return null
  30. }
  31. return notificationItem.items
  32. }
  33. static saveSeen(items: NotificationItemData[]) {
  34. let currentStorage: ?string = localStorage.getItem(this.storeName)
  35. let currentItems: NotificationItem[] = []
  36. if (currentStorage) {
  37. currentItems = (JSON.parse(currentStorage): NotificationItem[])
  38. currentItems = currentItems.filter(i => i.projectId !== Api.projectId)
  39. }
  40. let newItem: NotificationItem = {
  41. projectId: Api.projectId,
  42. items,
  43. }
  44. localStorage.setItem(this.storeName, JSON.stringify([
  45. ...currentItems,
  46. newItem,
  47. ]))
  48. }
  49. static clean(notificationItems: NotificationItemData[]) {
  50. let storageData = this.loadSeen()
  51. if (!storageData) {
  52. return
  53. }
  54. storageData = storageData.filter(i => notificationItems.find(j => i.id === j.id))
  55. this.saveSeen(storageData)
  56. }
  57. }
  58. class DataUtils {
  59. static getMainInfo(item: any) {
  60. if (item.type === 'migration') {
  61. return item
  62. }
  63. if (item.executions && item.executions.length) {
  64. let availableExecutions = item.executions.filter(i => !i.deleted_at)
  65. if (availableExecutions.length) {
  66. availableExecutions.sort((a, b) => b.number - a.number)
  67. return availableExecutions[0]
  68. }
  69. }
  70. return item
  71. }
  72. static getUpdatedAt(item: any) {
  73. let info = this.getMainInfo(item)
  74. return info.updated_at || info.created_at
  75. }
  76. static getItemDescription(item: any) {
  77. let type = item.type === 'replica' ? 'Replica' : 'Migration'
  78. let mainInfo = this.getMainInfo(item)
  79. let description = ''
  80. let id = `${mainInfo.id.substr(0, 7)}...`
  81. switch (mainInfo.status) {
  82. case 'COMPLETED':
  83. description = `${type} execution ${id} completed successfully`
  84. break
  85. case 'ERROR':
  86. description = `${type} execution ${id} failed`
  87. break
  88. case 'RUNNING':
  89. description = `${type} execution ${id} running`
  90. break
  91. default:
  92. break
  93. }
  94. return description
  95. }
  96. }
  97. class NotificationSource {
  98. async loadData(): Promise<NotificationItemData[]> {
  99. let [migrationsResponse, replicasResponse] = await Promise.all([
  100. Api.send({ url: `${servicesUrl.coriolis}/${Api.projectId}/migrations`, skipLog: true, quietError: true }),
  101. Api.send({ url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/detail`, skipLog: true, quietError: true }),
  102. ])
  103. let migrations = migrationsResponse.data.migrations
  104. let replicas = replicasResponse.data.replicas
  105. let apiData = [...migrations, ...replicas]
  106. apiData.sort((a, b) => moment(DataUtils.getUpdatedAt(b)).diff(DataUtils.getUpdatedAt(a)))
  107. let notificationItems: NotificationItemData[] = apiData.map(item => {
  108. let mainInfo = DataUtils.getMainInfo(item)
  109. let newItem: NotificationItemData = {
  110. id: item.id,
  111. status: mainInfo.status,
  112. type: item.type,
  113. name: item.instances[0],
  114. updatedAt: mainInfo.updated_at,
  115. description: DataUtils.getItemDescription(item),
  116. }
  117. return newItem
  118. }).filter(item => item.status).filter((item, i) => i < 10)
  119. let storageData = NotificationStorage.loadSeen()
  120. if (!storageData) {
  121. NotificationStorage.saveSeen(notificationItems)
  122. storageData = NotificationStorage.loadSeen() || []
  123. }
  124. notificationItems.forEach(item => {
  125. item.unseen = true
  126. // $FlowIgnore
  127. storageData.forEach(storageItem => {
  128. if (storageItem.id === item.id && storageItem.status === item.status && storageItem.updatedAt === item.updatedAt) {
  129. item.unseen = false
  130. }
  131. })
  132. })
  133. NotificationStorage.clean(notificationItems)
  134. return notificationItems
  135. }
  136. saveSeen(notificationItems: NotificationItemData[]) {
  137. NotificationStorage.saveSeen(notificationItems)
  138. }
  139. }
  140. export default new NotificationSource()