DashboardActivity.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. import * as React from 'react'
  15. import { observer } from 'mobx-react'
  16. import styled from 'styled-components'
  17. import { Link } from 'react-router-dom'
  18. import StatusIcon from '@src/components/ui/StatusComponents/StatusIcon'
  19. import StatusImage from '@src/components/ui/StatusComponents/StatusImage'
  20. import Button from '@src/components/ui/Button'
  21. import {
  22. InfoColumn, MainItemInfo, ItemReplicaBadge, ItemTitle, ItemDescription,
  23. } from '@src/components/ui/Dropdowns/NotificationDropdown'
  24. import type { NotificationItemData } from '@src/@types/NotificationItem'
  25. import { ThemePalette, ThemeProps } from '@src/components/Theme'
  26. import replicaImage from './images/replica.svg'
  27. const Wrapper = styled.div<any>`
  28. flex-grow: 1;
  29. `
  30. const Title = styled.div<any>`
  31. font-size: 24px;
  32. font-weight: ${ThemeProps.fontWeights.light};
  33. margin-bottom: 12px;
  34. `
  35. const Module = styled.div<any>`
  36. background: ${ThemePalette.grayscale[0]};
  37. display: flex;
  38. overflow: hidden;
  39. border-radius: ${ThemeProps.borderRadius};
  40. height: 273px;
  41. `
  42. const LoadingWrapper = styled.div<any>`
  43. width: 100%;
  44. height: 100%;
  45. display: flex;
  46. justify-content: center;
  47. align-items: center;
  48. overflow: hidden;
  49. `
  50. const List = styled.div<any>`
  51. width: 100%;
  52. display: flex;
  53. flex-direction: column;
  54. flex-wrap: wrap;
  55. `
  56. const ListItem = styled(Link)`
  57. padding: 8px 16px 8px 16px;
  58. cursor: pointer;
  59. text-decoration: none;
  60. color: inherit;
  61. display: block;
  62. transition: all ${ThemeProps.animations.swift};
  63. &:hover {
  64. background: ${ThemePalette.grayscale[1]};
  65. }
  66. `
  67. const NoItems = styled.div<any>`
  68. display: flex;
  69. flex-direction: column;
  70. align-items: center;
  71. width: 100%;
  72. `
  73. const ReplicaImage = styled.div<any>`
  74. ${ThemeProps.exactSize('148px')}
  75. background: url('${replicaImage}') center no-repeat;
  76. `
  77. const Message = styled.div<any>`
  78. text-align: center;
  79. margin-bottom: 32px;
  80. `
  81. type Props = {
  82. notificationItems: NotificationItemData[],
  83. style?: React.CSSProperties | null,
  84. loading?: boolean,
  85. large?: boolean,
  86. onNewClick?: () => void,
  87. }
  88. @observer
  89. class DashboardActivity extends React.Component<Props> {
  90. renderList() {
  91. return (
  92. <List>
  93. {this.props.notificationItems
  94. .filter((_, i) => i < (this.props.large ? 10 : 5)).map((item, i) => {
  95. const executionsHref = item.status === 'RUNNING' ? item.type === 'replica' ? '/executions' : item.type === 'migration' ? '/tasks' : '' : ''
  96. return (
  97. <ListItem
  98. key={item.id}
  99. to={`/${item.type}s/${item.id}${executionsHref}`}
  100. style={{
  101. width: `calc(${this.props.large ? 50 : 100}% - 32px)`,
  102. paddingTop: (i === 0 || i === 5) ? '16px' : '8px',
  103. }}
  104. >
  105. <InfoColumn>
  106. <MainItemInfo>
  107. <StatusIcon status={item.status} hollow />
  108. <ItemReplicaBadge
  109. type={item.type}
  110. >{item.type === 'replica' ? 'RE' : 'MI'}
  111. </ItemReplicaBadge>
  112. <ItemTitle nowrap>{item.name}</ItemTitle>
  113. </MainItemInfo>
  114. <ItemDescription>{item.description}</ItemDescription>
  115. </InfoColumn>
  116. </ListItem>
  117. )
  118. })}
  119. </List>
  120. )
  121. }
  122. renderNoItems() {
  123. return (
  124. <NoItems>
  125. <ReplicaImage />
  126. <Message>There is no recent activity<br />in this project.</Message>
  127. <Button
  128. hollow
  129. primary
  130. transparent
  131. onClick={this.props.onNewClick}
  132. >New Replica / Migration
  133. </Button>
  134. </NoItems>
  135. )
  136. }
  137. renderLoading() {
  138. return (
  139. <LoadingWrapper>
  140. <StatusImage status="RUNNING" />
  141. </LoadingWrapper>
  142. )
  143. }
  144. render() {
  145. return (
  146. <Wrapper style={this.props.style}>
  147. <Title>Recent Activity</Title>
  148. <Module>
  149. {this.props.notificationItems.length === 0 && this.props.loading
  150. ? this.renderLoading() : this.props.notificationItems.length
  151. ? this.renderList() : this.renderNoItems()}
  152. </Module>
  153. </Wrapper>
  154. )
  155. }
  156. }
  157. export default DashboardActivity