jcloud/dashboard/src2/components/SiteUpdateDialog.vue

229 lines
5.8 KiB
Vue

<template>
<Dialog
v-model="show"
:options="{
title: dialogTitle,
size: '2xl',
}"
>
<template #body-content>
<template v-if="updatableApps.length > 0">
<GenericList :options="listOptions" />
<div class="mt-4 flex flex-col space-y-4">
<DateTimeControl v-model="scheduledTime" label="计划时间" />
<div class="flex flex-col space-y-2">
<FormControl
label="跳过失败的补丁(如果有)"
type="checkbox"
v-model="skipFailingPatches"
/>
<FormControl
label="跳过本次更新的备份(如果更新失败,将无法回滚)"
type="checkbox"
v-model="skipBackups"
/>
</div>
</div>
</template>
<div v-else class="text-center text-base text-gray-600">
没有可更新的应用
</div>
<ErrorMessage class="mt-4" :message="$site.scheduleUpdate.error" />
</template>
<template #actions>
<Button
v-if="existingUpdate"
class="w-full"
variant="solid"
label="编辑更新"
@click="editUpdate"
/>
<Button
v-else
class="w-full"
variant="solid"
:loading="$site.scheduleUpdate.loading"
:label="`${scheduledTime ? `在 ${scheduledTimeInLocal}` : '立即'} 更新`"
@click="scheduleUpdate"
/>
</template>
</Dialog>
</template>
<script>
import { getCachedDocumentResource } from 'jingrow-ui';
import DateTimeControl from './DateTimeControl.vue';
import GenericList from './GenericList.vue';
import dayjs, { dayjsIST } from '../utils/dayjs';
import { toast } from 'vue-sonner';
export default {
name: 'SiteUpdateDialog',
props: {
site: {
type: String,
required: true,
},
existingUpdate: String,
},
components: {
GenericList,
DateTimeControl,
},
data() {
return {
show: true,
skipFailingPatches: false,
scheduledTime: '',
skipBackups: false,
};
},
resources: {
siteUpdate() {
return {
// for some reason, type: document won't work after the first time
// TODO: investigate why
url: 'jcloud.api.client.get',
params: {
pagetype: 'Site Update',
name: this.existingUpdate,
},
auto: !!this.existingUpdate,
onSuccess: (pg) => {
this.initializeValues(pg);
},
};
},
},
computed: {
scheduledTimeInIST() {
if (!this.scheduledTime) return;
return dayjsIST(this.scheduledTime).format('YYYY-MM-DDTHH:mm');
},
scheduledTimeInLocal() {
return dayjs(this.scheduledTime).format('YYYY-MM-DD HH:mm');
},
listOptions() {
return {
data: this.updatableApps.filter(
(app) => app.current_hash !== app.next_hash,
),
columns: [
{
label: '应用',
fieldname: 'app',
format(value, row) {
return row.title || value;
},
},
{
label: '当前版本',
type: 'Badge',
format(value, row) {
return row.will_branch_change
? row.current_branch
: row.current_tag || row.current_hash.slice(0, 7);
},
link(value, row) {
if (row.will_branch_change) {
return `${row.repository_url}/tree/${row.current_branch}`;
}
if (row.current_tag) {
return `${row.repository_url}/releases/tag/${row.current_tag}`;
}
if (row.current_hash) {
return `${row.repository_url}/commit/${row.current_hash}`;
}
},
},
{
label: '下一个版本',
type: 'Badge',
format(value, row) {
return row.will_branch_change
? row.branch
: row.next_tag || row.next_hash.slice(0, 7);
},
link(value, row) {
if (row.will_branch_change) {
return `${row.repository_url}/tree/${row.branch}`;
}
if (row.next_tag) {
return `${row.repository_url}/releases/tag/${row.next_tag}`;
}
if (row.next_hash) {
return `${row.repository_url}/commit/${row.next_hash}`;
}
},
},
],
};
},
updatableApps() {
if (!this.$site.pg.update_information.update_available) return [];
let installedApps = this.$site.pg.update_information.installed_apps.map(
(d) => d.app,
);
return this.$site.pg.update_information.apps.filter((app) =>
installedApps.includes(app.app),
);
},
$site() {
return getCachedDocumentResource('Site', this.site);
},
siteUpdate() {
return this.$resources.siteUpdate;
},
dialogTitle() {
if (this.existingUpdate) return '编辑计划更新';
else return '有可用更新';
},
},
methods: {
scheduleUpdate() {
this.$site.scheduleUpdate.submit(
{
skip_failing_patches: this.skipFailingPatches,
skip_backups: this.skipBackups,
scheduled_time: this.scheduledTimeInIST,
},
{
onSuccess: () => {
this.$site.reload();
this.show = false;
this.$router.push({ name: 'Site Detail Updates' });
},
},
);
},
editUpdate() {
toast.promise(
this.$site.editScheduledUpdate.submit({
name: this.existingUpdate,
skip_failing_patches: this.skipFailingPatches,
skip_backups: this.skipBackups,
scheduled_time: this.scheduledTimeInIST,
}),
{
loading: '正在编辑计划更新...',
success: () => {
this.show = false;
this.$site.reload();
this.siteUpdate.reload();
return '计划更新编辑成功';
},
error: (err) => {
return err.messages.length
? err.messages[0]
: err.message || '编辑计划更新失败';
},
},
);
},
initializeValues(pg) {
this.skipFailingPatches = pg.skipped_failing_patches;
this.skipBackups = pg.skipped_backups;
this.scheduledTime = dayjs(pg.scheduled_time).format('YYYY-MM-DDTHH:mm');
},
},
};
</script>