index.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import $ from 'jquery';
  2. import unique from 'mout/array/unique';
  3. import { config, translations } from 'grav-config';
  4. import formatBytes from '../utils/formatbytes';
  5. import { Instance as gpm } from '../utils/gpm';
  6. import Notifications from './notifications';
  7. import Feed from './feed';
  8. import './check';
  9. import './update';
  10. import './channel-switcher';
  11. export default class Updates {
  12. constructor(payload = {}) {
  13. this.setPayload(payload);
  14. this.task = `task${config.param_sep}`;
  15. }
  16. setPayload(payload = {}) {
  17. this.payload = payload;
  18. return this;
  19. }
  20. fetch(force = false) {
  21. gpm.fetch((response) => this.setPayload(response), force);
  22. return this;
  23. }
  24. maintenance(mode = 'hide') {
  25. let element = $('#updates [data-update-packages]');
  26. element[mode === 'show' ? 'fadeIn' : 'fadeOut']();
  27. if (mode === 'hide') {
  28. $('.badges.with-updates').removeClass('with-updates').find('.badge.updates').remove();
  29. }
  30. return this;
  31. }
  32. grav() {
  33. let payload = this.payload.grav;
  34. if (payload && payload.isUpdatable) {
  35. let task = this.task;
  36. let bar = '';
  37. if (!payload.isSymlink) {
  38. bar += `<button data-maintenance-update="${config.base_url_relative}/update.json/${task}updategrav/admin-nonce${config.param_sep}${config.admin_nonce}" class="button button-small secondary" id="grav-update-button">${translations.PLUGIN_ADMIN.UPDATE_GRAV_NOW}</button>`;
  39. } else {
  40. bar += `<span class="hint--left" style="float: right;" data-hint="${translations.PLUGIN_ADMIN.GRAV_SYMBOLICALLY_LINKED}"><i class="fa fa-fw fa-link"></i></span>`;
  41. }
  42. bar += `
  43. Grav <b>v${payload.available}</b> ${translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE}! <span class="less">(${translations.PLUGIN_ADMIN.CURRENT} v${payload.version})</span>
  44. `;
  45. let element = $('[data-gpm-grav]').removeClass('hidden');
  46. if (element.is(':empty')) {
  47. element.hide();
  48. }
  49. element
  50. .addClass('grav')
  51. .html(`${bar}`)
  52. .slideDown(150)
  53. .parent('#messages').addClass('default-box-shadow');
  54. }
  55. $('#grav-update-button').on('click', function() {
  56. $(this).html(`${translations.PLUGIN_ADMIN.UPDATING_PLEASE_WAIT} ${formatBytes(payload.assets['grav-update'].size)}..`);
  57. });
  58. return this;
  59. }
  60. resources() {
  61. if (!this.payload || !this.payload.resources || !this.payload.resources.total) {
  62. return this.maintenance('hide');
  63. }
  64. let is_current_package_latest = true;
  65. let map = ['plugins', 'themes'];
  66. let singles = ['plugin', 'theme'];
  67. let { plugins, themes } = this.payload.resources;
  68. if (!this.payload.resources.total) { return this; }
  69. [plugins, themes].forEach(function(resources, index) {
  70. if (!resources || Array.isArray(resources)) { return; }
  71. let length = Object.keys(resources).length;
  72. let type = map[index];
  73. // sidebar
  74. $(`#admin-menu a[href$="/${map[index]}"]`)
  75. .find('.badges')
  76. .addClass('with-updates')
  77. .find('.badge.updates').text(length);
  78. var type_translation = '';
  79. // update all
  80. if (type === 'plugins') {
  81. type_translation = translations.PLUGIN_ADMIN.PLUGINS;
  82. } else {
  83. type_translation = translations.PLUGIN_ADMIN.THEMES;
  84. }
  85. let updateAll = $(`.grav-update.${type}`);
  86. updateAll.css('display', 'block').html(`
  87. <p>
  88. <a href="#" class="button button-small secondary" data-remodal-target="update-packages" data-packages-slugs="${Object.keys(resources).join()}" data-${singles[index]}-action="start-packages-update">${translations.PLUGIN_ADMIN.UPDATE} ${translations.PLUGIN_ADMIN.ALL} ${type_translation}</a>
  89. <i class="fa fa-bullhorn"></i>
  90. ${length} ${translations.PLUGIN_ADMIN.OF_YOUR} ${type} ${translations.PLUGIN_ADMIN.HAVE_AN_UPDATE_AVAILABLE}
  91. </p>
  92. `);
  93. let existing_slugs = $('[data-update-packages]').attr('data-packages-slugs') || '';
  94. if (existing_slugs) {
  95. existing_slugs = existing_slugs.split(',');
  96. } else {
  97. existing_slugs = [];
  98. }
  99. let slugs = unique(existing_slugs.concat(Object.keys(resources))).join();
  100. $('[data-update-packages]').attr('data-packages-slugs', `${slugs}`);
  101. Object.keys(resources).forEach(function(item) {
  102. // listing page
  103. let container = $(`[data-gpm-${singles[index]}="${item}"]`);
  104. let element = container.find('.gpm-name');
  105. let url = element.find('a');
  106. let content_wrapper = container.parents('.content-wrapper');
  107. if (type === 'plugins' && !element.find('.badge.update').length) {
  108. element.append(`<a class="plugin-update-button" href="${url.attr('href')}"><span class="badge update">${translations.PLUGIN_ADMIN.UPDATE_AVAILABLE}!</span></a>`);
  109. content_wrapper.addClass('has-updates');
  110. } else if (type === 'themes') {
  111. element.append(`<div class="gpm-ribbon"><a href="${url.attr('href')}">${translations.PLUGIN_ADMIN.UPDATE.toUpperCase()}</a></div>`);
  112. content_wrapper.addClass('has-updates');
  113. }
  114. // details page
  115. if (container.length) {
  116. let details = $(`.grav-update.${singles[index]}`);
  117. if (details.length) {
  118. let releaseType = resources[item].type === 'testing' ? '<span class="gpm-testing">test release</span>' : '';
  119. details.html(`
  120. <p>
  121. <a href="#" class="button button-small secondary" data-remodal-target="update-packages" data-packages-slugs="${item}" data-${singles[index]}-action="start-package-installation">${translations.PLUGIN_ADMIN.UPDATE} ${singles[index].charAt(0).toUpperCase() + singles[index].substr(1).toLowerCase()}</a>
  122. <i class="fa fa-bullhorn"></i>
  123. <strong>v${resources[item].available}</strong> ${releaseType} ${translations.PLUGIN_ADMIN.OF_THIS} ${singles[index]} ${translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE}!
  124. </p>
  125. `).css('display', 'block');
  126. is_current_package_latest = false;
  127. }
  128. }
  129. });
  130. $('[data-update-packages]').removeClass('hidden');
  131. });
  132. $('.content-wrapper').addClass('updates-checked');
  133. if (!is_current_package_latest) {
  134. $('.warning-reinstall-not-latest-release').removeClass('hidden');
  135. }
  136. }
  137. }
  138. let Instance = new Updates();
  139. export { Instance, Notifications, Feed };
  140. // automatically refresh UI for updates (graph, sidebar, plugin/themes pages) after every fetch
  141. gpm.on('fetched', (response, raw) => {
  142. Instance.setPayload(response.payload || {});
  143. Instance.grav().resources();
  144. });
  145. if (config.enable_auto_updates_check === '1') {
  146. gpm.fetch();
  147. }