Finish button of BS update

This commit is contained in:
Pig Fang 2018-09-13 18:10:23 +08:00
parent 6bfe30b394
commit 43051bad90
7 changed files with 188 additions and 115 deletions

View File

@ -0,0 +1,113 @@
<template>
<span>
<button
v-if="!updating"
class="btn btn-primary"
:disabled="!canUpdate"
@click="update"
>{{ $t('admin.updateButton') }}</button>
<button v-else disabled class="btn btn-primary">
<i class="fa fa-spinner fa-spin"></i> {{ $t('admin.preparing') }}
</button>
<div
id="modal-start-download"
class="modal fade"
tabindex="-1"
role="dialog"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" v-t="'admin.downloading'"></h4>
</div>
<div class="modal-body">
<p>{{ $t('admin.updateSize') }}<span>{{ total }}</span> KB</p>
<div class="progress">
<div
class="progress-bar progress-bar-striped active"
role="progressbar"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
:style="{ width: `${percentage}%` }"
>
<span>{{ ~~percentage }}</span>%
</div>
</div>
</div>
</div>
</div>
</div>
</span>
</template>
<script>
import { swal } from '../../js/notify';
const POLLING_INTERVAL = 500;
export default {
name: 'UpdateButton',
data: () => ({
canUpdate: blessing.extra.canUpdate,
updating: false,
total: 0,
downloaded: 0,
}),
computed: {
percentage() {
return this.downloaded / this.total * 100;
}
},
methods: {
async update() {
this.updating = true;
await this.takeAction('prepare-download');
this.updating && $('#modal-start-download').modal({
backdrop: 'static',
keyboard: false
});
setTimeout(this.polling, POLLING_INTERVAL);
this.updating && await this.takeAction('start-download');
this.updating && await this.takeAction('extract');
this.updating = false;
if (this.downloaded) {
await swal({ type: 'success', text: this.$t('admin.updateCompleted') });
window.location = blessing.base_url;
}
},
async takeAction(action) {
const { errno, msg } = await this.$http.post('/admin/update/download', {
action
});
if (errno && errno !== 0) {
swal({ type: 'error', text: msg });
this.updating = false;
}
},
async polling() {
const { downloaded, total } = await this.$http.get(
'/admin/update/download',
{ action: 'get-progress' }
);
this.downloaded = ~~(+downloaded / 1024);
this.total = ~~(+total / 1024);
this.updating && setTimeout(this.polling, POLLING_INTERVAL);
}
}
};
</script>

View File

@ -44,6 +44,11 @@ export default [
component: () => import('./admin/Market'), component: () => import('./admin/Market'),
el: '.content' el: '.content'
}, },
{
path: 'admin/update',
component: () => import('./admin/Update'),
el: '#update-button'
},
{ {
path: 'auth/login', path: 'auth/login',
component: () => import('./auth/Login'), component: () => import('./auth/Login'),

View File

@ -1,110 +0,0 @@
'use strict';
async function downloadUpdates() {
console.log('Prepare trno download');
try {
const preparation = await fetch({
url: url('admin/update/download?action=prepare-download'),
type: 'GET',
dataType: 'json',
beforeSend: function() {
$('#update-button').html(
'<i class="fa fa-spinner fa-spin"></i> ' + trans('admin.preparing')
).prop('disabled', 'disabled');
}
});
console.log(preparation);
const { file_size: fileSize } = preparation;
$('#file-size').html(fileSize);
$('#modal-start-download').modal({
'backdrop': 'static',
'keyboard': false
});
console.log('Start downloading');
// Downloading progress polling
const interval_id = setInterval(progressPolling(fileSize), 300);
const download = await fetch({
url: url('admin/update/download?action=start-download'),
type: 'POST',
dataType: 'json'
});
clearInterval(interval_id);
console.log('Downloading finished');
console.log(download);
$('.modal-title').html('<i class="fa fa-spinner fa-spin"></i> ' + trans('admin.extracting'));
$('.modal-body').append(`<p>${trans('admin.downloadCompleted')}</p>`);
console.log('Start extracting');
const extract = await fetch({
url: url('admin/update/download?action=extract'),
type: 'POST',
dataType: 'json'
});
console.log('Package extracted and files are covered');
$('#modal-start-download').modal('toggle');
swal({
type: 'success',
html: extract.msg
}).then(function () {
window.location = url('/');
}, function () {
window.location = url('/');
});
} catch (error) {
showAjaxError(error);
}
}
function progressPolling(fileSize) {
return async () => {
try {
const { size } = await fetch({
url: url('admin/update/download?action=get-file-size'),
type: 'GET'
});
const progress = (size / fileSize * 100).toFixed(2);
$('#imported-progress').html(progress);
$('.progress-bar')
.css('width', progress + '%')
.attr('aria-valuenow', progress);
} catch (error) {
// No need to show error if failed to get size
}
};
}
async function checkForUpdates() {
try {
const data = await fetch({ url: url('admin/update/check') });
if (data.available === true) {
const dom = `<span class="label label-primary pull-right">v${data.latest}</span>`;
$(`[href="${url('admin/update')}"]`).append(dom);
}
} catch (error) {
//
}
}
if (process.env.NODE_ENV === 'test') {
module.exports = {
checkForUpdates,
progressPolling,
downloadUpdates,
};
}

View File

@ -0,0 +1,55 @@
import Vue from 'vue';
import { mount } from '@vue/test-utils';
import { flushPromises } from '../../utils';
import Update from '@/components/admin/Update.vue';
import '@/js/notify';
jest.mock('@/js/notify');
afterEach(() => {
window.blessing.extra = { canUpdate: true };
});
test('button should be disabled if update is unavailable', () => {
window.blessing.extra = { canUpdate: false };
const wrapper = mount(Update);
expect(wrapper.find('.btn').attributes('disabled')).toBe('disabled');
});
test('perform update', async () => {
window.$ = jest.fn(() => ({
modal() {}
}));
Vue.prototype.$http.post
.mockResolvedValueOnce({ errno: 1 })
.mockResolvedValue({});
Vue.prototype.$http.get
.mockResolvedValue({ total: 2048, downloaded: 2048 });
const wrapper = mount(Update);
const button = wrapper.find('.btn');
button.trigger('click');
await flushPromises();
expect(window.$).not.toBeCalled();
expect(Vue.prototype.$http.post).toBeCalledWith(
'/admin/update/download',
{ action: 'prepare-download' }
);
button.trigger('click');
jest.runOnlyPendingTimers();
await flushPromises();
expect(window.$).toBeCalled();
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/update/download',
{ action: 'get-progress' }
);
expect(Vue.prototype.$http.post).toBeCalledWith(
'/admin/update/download',
{ action: 'start-download' }
);
expect(Vue.prototype.$http.post).toBeCalledWith(
'/admin/update/download',
{ action: 'extract' }
);
});

View File

@ -291,9 +291,11 @@ admin:
may be not compatible with the current version of Blessing Skin, and may be not compatible with the current version of Blessing Skin, and
enabling it may cause unexpected problems. Do you really want to enable the enabling it may cause unexpected problems. Do you really want to enable the
plugin? plugin?
updateButton: Update Now
updateSize: "Size of package:"
preparing: Preparing preparing: Preparing
downloadCompleted: Update package download completed. downloading: Downloading update package...
extracting: Extracting update package.. updateCompleted: Update completed.
change-color: change-color:
title: Change theme color title: Change theme color
success: Theme color updated. success: Theme color updated.

View File

@ -285,9 +285,11 @@ admin:
noDependenciesNotice: >- noDependenciesNotice: >-
此插件没有声明任何依赖关系,这代表它有可能并不兼容此版本的 Blessing 此插件没有声明任何依赖关系,这代表它有可能并不兼容此版本的 Blessing
Skin请将此插件升级至可能的最新版本。强行启用可能导致无法预料的后果。你确定要启用此插件吗 Skin请将此插件升级至可能的最新版本。强行启用可能导致无法预料的后果。你确定要启用此插件吗
updateButton: 马上升级
updateSize: 更新包大小:
preparing: 正在准备 preparing: 正在准备
downloadCompleted: 更新包下载完成 downloading: 正在下载更新包
extracting: 正在解压更新包 updateCompleted: 更新完成
change-color: change-color:
title: 更改配色 title: 更改配色
success: 修改配色成功 success: 修改配色成功

View File

@ -94,7 +94,7 @@
@endif @endif
</div><!-- /.box-body --> </div><!-- /.box-body -->
<div class="box-footer"> <div class="box-footer">
<a class="btn btn-primary" id="update-button" {!! !$info['new_version_available'] ? 'disabled="disabled"' : 'onclick="downloadUpdates();"' !!}>@lang('admin.update.info.button')</a> <span id="update-button"></span>
{!! trans('admin.update.info.check-github', ['url' => 'https://github.com/printempw/blessing-skin-server/releases']) !!} {!! trans('admin.update.info.check-github', ['url' => 'https://github.com/printempw/blessing-skin-server/releases']) !!}
</div> </div>
</div> </div>
@ -132,4 +132,10 @@
</div><!-- /.modal-dialog --> </div><!-- /.modal-dialog -->
</div><!-- /.modal --> </div><!-- /.modal -->
<script>
blessing.extra = {
canUpdate: {{ $info['new_version_available'] ? 'true' : 'false' }}
}
</script>
@endsection @endsection