mirror of
https://github.com/bs-community/blessing-skin-server.git
synced 2024-12-21 06:19:38 +08:00
Finish button of BS update
This commit is contained in:
parent
6bfe30b394
commit
43051bad90
113
resources/assets/src/components/admin/Update.vue
Normal file
113
resources/assets/src/components/admin/Update.vue
Normal 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">×</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>
|
@ -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'),
|
||||||
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
55
resources/assets/tests/components/admin/Update.test.js
Normal file
55
resources/assets/tests/components/admin/Update.test.js
Normal 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' }
|
||||||
|
);
|
||||||
|
});
|
@ -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.
|
||||||
|
@ -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: 修改配色成功
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user