You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ProjectUpdate.vue 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <template>
  2. <div v-if="isReady" class="update">
  3. <div class="update__info">
  4. <!-- Logo -->
  5. <figure>
  6. <img :src="data.logo">
  7. </figure>
  8. <h1 class="title">
  9. {{ data.name }} <span v-tooltip="'New version'">{{ updater.latestCompatible.tag_name }}</span>
  10. </h1>
  11. <h2 v-if="!updater.update.active" class="subtitle">
  12. {{ data.description }}
  13. </h2>
  14. </div>
  15. <!-- Preparing -->
  16. <div v-if="isPreparing" class="update__status">
  17. Preparing download...
  18. </div>
  19. <!-- Downloading -->
  20. <div v-else-if="isDownloading && updater.update.progress >= 0" class="update__status">
  21. Downloading ~ <strong>{{ updater.update.progress }}%</strong> ~ {{ updater.update.written | size }}/{{ updater.update.total | size }} MB. <span v-if="updater.update.peers > 0">({{ updater.update.peers }} peers)</span>
  22. </div>
  23. <!-- Downloading -->
  24. <div v-else-if="isDownloading" class="update__status">
  25. Downloading ~ {{ updater.update.written | size }} MB.
  26. </div>
  27. <!-- Installing -->
  28. <div v-else-if="isInstalling" class="update__status">
  29. Installing...
  30. </div>
  31. <!-- Download Progress -->
  32. <div v-if="isDownloading && updater.update.progress >= 0" class="update__progressbar">
  33. <progress min="0" max="100" :value="updater.update.progress" />
  34. </div>
  35. <!-- Actions -->
  36. <div class="update__actions">
  37. <button v-if="!updater.enabled"
  38. key="update-disabled"
  39. v-tooltip="'This component cannot be updated until the problem explained above is fixed.'"
  40. class="button button--success"
  41. disabled>
  42. <span class="icon"><font-awesome-icon icon="sync" /></span>
  43. Update
  44. </button>
  45. <button v-else-if="!updater.update.active"
  46. key="update-start"
  47. class="button button--success"
  48. @click.prevent="updater.start()">
  49. <span class="icon"><font-awesome-icon icon="sync" /></span>
  50. Update
  51. </button>
  52. <button v-if="updater.update.active"
  53. key="update-cancel"
  54. class="button button--danger"
  55. @click.prevent="updater.cancel()">
  56. <span class="icon"><font-awesome-icon icon="stop" /></span>
  57. Cancel
  58. </button>
  59. <button v-if="updater.downloadUrls.length > 0"
  60. v-tooltip="'List of links to download the update manually.'"
  61. class="button button--info"
  62. @click.prevent="$refs.mirrorsDialog.showModal()">
  63. <span class="icon"><font-awesome-icon icon="link" /></span>
  64. Mirrors
  65. </button>
  66. <button v-else
  67. v-tooltip="'List of links to download the update manually.'"
  68. class="button button--info"
  69. disabled>
  70. <span class="icon"><font-awesome-icon icon="link" /></span>
  71. Mirrors
  72. </button>
  73. </div>
  74. <!-- Project buttons -->
  75. <div class="update__actions__extra">
  76. <a v-for="(item, index) in data.data.navigation"
  77. :key="index"
  78. :href="item.
  79. ref"
  80. target="_blank"
  81. class="button button--sm">{{ item.label }}</a>
  82. </div>
  83. <!-- Hint -->
  84. <div class="update__hint">
  85. <p>
  86. <a href="https://time.dreamnet.tech/docs/guide/updater" target="_blank">
  87. <font-awesome-icon icon="exclamation-circle" />
  88. Troubleshooting
  89. </a>
  90. </p>
  91. </div>
  92. <!-- Mirrors Dialog -->
  93. <dialog ref="mirrorsDialog">
  94. <div class="dialog__content">
  95. <ul class="mirrors">
  96. <li v-for="(url, index) in updater.downloadAllUrls" :key="index">
  97. <a v-if="isTorrent(url)" :href="url" target="_blank">Torrent ({{ url | domain }})</a>
  98. <a v-else-if="isIPFS(url)" :href="`https://gateway.ipfs.io/ipfs/${url}?filename=${updater.filename}`" target="_blank">IPFS</a>
  99. <a v-else :href="url" target="_blank">HTTP ({{ url | domain }})</a>
  100. </li>
  101. </ul>
  102. <div class="dialog__buttons">
  103. <button class="button button--danger" @click.prevent="$refs.mirrorsDialog.close()">
  104. Close
  105. </button>
  106. </div>
  107. </div>
  108. </dialog>
  109. </div>
  110. </template>
  111. <script>
  112. import { toNumber, startsWith, endsWith } from 'lodash'
  113. import * as projects from '~/modules/projects'
  114. export default {
  115. filters: {
  116. progress(value) {
  117. value = toNumber(value).toFixed(2)
  118. return `${value}%`
  119. },
  120. size(value) {
  121. value = toNumber(value).toFixed(2)
  122. return value
  123. },
  124. domain(value) {
  125. if (startsWith(value, 'magnet:')) {
  126. return 'magnet'
  127. }
  128. return (new URL(value)).hostname
  129. },
  130. },
  131. props: {
  132. project: {
  133. type: String,
  134. required: true,
  135. },
  136. },
  137. data: () => ({
  138. data: null,
  139. }),
  140. computed: {
  141. updater() {
  142. return this.data.updater
  143. },
  144. isReady() {
  145. return this.updater
  146. },
  147. currentVersion() {
  148. return this.updater?.currentVersion || 'v0.0.0'
  149. },
  150. isPreparing() {
  151. return this.updater?.update?.status === 'preparing'
  152. },
  153. isDownloading() {
  154. return this.updater?.update?.status === 'downloading'
  155. },
  156. isInstalling() {
  157. return this.updater?.update?.status === 'installing'
  158. },
  159. },
  160. created() {
  161. // eslint-disable-next-line import/namespace
  162. this.data = projects[this.project]
  163. },
  164. beforeDestroy() {
  165. this.updater.cancel()
  166. },
  167. methods: {
  168. isTorrent(url) {
  169. return startsWith(url, 'magnet:') || endsWith(url, '.torrent')
  170. },
  171. isIPFS(url) {
  172. return startsWith(url, 'Qm')
  173. },
  174. },
  175. }
  176. </script>
  177. <style lang="scss" scoped>
  178. .update {
  179. @apply flex flex-col items-center justify-center;
  180. }
  181. .update__info {
  182. @apply text-center mb-6;
  183. figure {
  184. @apply mb-4 text-6xl;
  185. img {
  186. @apply inline-block;
  187. height: 100px;
  188. }
  189. }
  190. .title {
  191. @apply text-2xl text-white font-semibold;
  192. span {
  193. @apply text-primary-500 font-bold;
  194. cursor: help;
  195. }
  196. }
  197. .subtitle {
  198. @apply text-lg;
  199. }
  200. }
  201. .update__status {
  202. @apply mb-4 text-lg;
  203. }
  204. .update__progressbar {
  205. @apply mb-4;
  206. width: 80%;
  207. progress {
  208. @apply w-full border-0 bg-dark-600;
  209. height: 18px;
  210. border-radius: 9px;
  211. &::-webkit-progress-bar {
  212. @apply bg-dark-500;
  213. border-radius: 9px;
  214. }
  215. &::-webkit-progress-value {
  216. @apply bg-primary-500;
  217. border-radius: 9px;
  218. }
  219. }
  220. }
  221. .update__actions {
  222. @apply mb-4;
  223. .button {
  224. &:not(:last-child) {
  225. @apply mr-4;
  226. }
  227. }
  228. }
  229. .update__actions__extra {
  230. @apply mb-6;
  231. .button {
  232. &:not(:last-child) {
  233. @apply mr-2;
  234. }
  235. }
  236. }
  237. .update__hint {
  238. @apply text-sm;
  239. a {
  240. @apply text-white underline;
  241. }
  242. }
  243. .mirrors {
  244. @apply list-disc ml-6;
  245. a:hover {
  246. @apply underline;
  247. }
  248. }
  249. </style>