jcloud/dashboard/src2/views/site/NewSiteRestore.vue

268 lines
6.8 KiB
Vue

<template>
<div>
<label class="text-lg font-semibold"> Restore an existing site </label>
<p class="text-base text-gray-700">
Restore an existing site from backup files or directly from site url.
</p>
<div class="mt-4 grid grid-cols-2 gap-6">
<Button
v-for="tab in [
{ name: 'Upload Backups', key: 'backup' },
{ name: 'Migrate from Site URL', key: 'siteUrl' }
]"
:key="tab.key"
:type="restoreFrom === tab.key ? 'primary' : 'secondary'"
@click="restoreFrom = tab.key"
>
{{ tab.name }}
</Button>
</div>
<div v-if="restoreFrom === 'backup'">
<div
class="mt-6 rounded-md border border-gray-300 px-4 py-3 text-sm text-gray-700"
>
<ol class="list-decimal pl-4">
<li>Login to your site.</li>
<li>From the Download Backups page, download the latest backup.</li>
<li>
To get files backup, click on Download Files Backup. This will
generate a new files backup and you will get an email.
</li>
<li>
Download the files backup from the links in the email and upload the
files here.
</li>
</ol>
</div>
<Alert class="mt-5 w-full" v-if="manualMigration">
Seems like your site is huge. Open a support ticket mentioning that you
want to restore a backup and it's size and we'll take it from there.
</Alert>
<BackupFilesUploader
class="mt-6"
:backupFiles="selectedFiles"
@update:backupFiles="files => $emit('update:selectedFiles', files)"
/>
</div>
<div v-if="restoreFrom === 'siteUrl'">
<div class="mt-6">
<div
class="rounded-md border border-gray-300 px-4 py-3 text-sm text-gray-700"
>
<ol class="list-decimal pl-4">
<li>Login to your site.</li>
<li>
From the Download Backups page, click on Download Files Backup.
</li>
<li>
This will generate a new files backup and you will get an email.
</li>
<li>After that, come back here and click on Get Backups.</li>
</ol>
</div>
<Alert
class="mt-5 w-full"
v-if="
errorContains('Your site exceeds the limits for this operation')
"
>
Seems like your site is huge. Open a support ticket mentioning that
you want to restore a backup and it's size and we'll take it from
there.
</Alert>
<Form
class="mt-6"
:fields="[
{
label: 'Site URL',
fieldtype: 'Data',
fieldname: 'url'
},
{
label: 'Email',
fieldtype: 'Data',
fieldname: 'email'
},
{
label: 'Password',
fieldtype: 'Password',
fieldname: 'password'
}
]"
v-model="jingrowSite"
/>
<div class="mt-2">
<ErrorMessage
:message="$resources.getBackupLinks.error"
v-if="!$resources.getBackupLinks.data"
/>
<div
class="text-base font-semibold text-green-500"
v-if="$resources.getBackupLinks.data"
>
Found latest backups at {{ fetchedBackupFiles[0].timestamp }}
</div>
<div class="mt-2 space-y-1" v-if="$resources.getBackupLinks.data">
<div v-for="file in fetchedBackupFiles" :key="file.remote_file">
<div class="text-base font-medium text-gray-700">
{{ file.file_name }}
</div>
</div>
</div>
</div>
<Button
v-if="!$resources.getBackupLinks.data"
class="mt-2"
@click="$resources.getBackupLinks.submit()"
:loading="$resources.getBackupLinks.loading"
>
Get Backups
</Button>
</div>
</div>
<div class="mt-3" v-if="['backup', 'siteUrl'].includes(restoreFrom)">
<!-- Skip Failing Checkbox -->
<input
id="skip-failing"
type="checkbox"
class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
v-model="wantToSkipFailingPatches"
/>
<label for="skip-failing" class="ml-2 text-sm text-gray-900">
Skip failing patches (if any patch fails)
</label>
</div>
</div>
</template>
<script>
import FileUploader from '@/components/FileUploader.vue';
import Form from '@/components/Form.vue';
import BackupFilesUploader from '@/components/BackupFilesUploader.vue';
import { DateTime } from 'luxon';
export default {
name: 'Restore',
emits: ['update:selectedFiles', 'update:skipFailingPatches'],
props: ['selectedFiles', 'manualMigration', 'skipFailingPatches'],
components: {
FileUploader,
Form,
BackupFilesUploader
},
data() {
return {
restoreFrom: null,
files: [
{
icon: 'database',
type: 'database',
ext: 'application/x-gzip',
title: 'Database Backup',
file: null
},
{
icon: 'file',
type: 'public',
ext: 'application/x-tar',
title: 'Public Files',
file: null
},
{
icon: 'file-minus',
type: 'private',
ext: 'application/x-tar',
title: 'Private Files',
file: null
},
{
icon: 'file-minus',
type: 'config',
ext: 'application/json',
title: 'Config Files',
file: null
}
],
uploadedFiles: {
database: null,
public: null,
private: null
},
jingrowSite: {
url: '',
email: '',
password: ''
},
errorMessage: null,
wantToSkipFailingPatches: false
};
},
resources: {
getBackupLinks() {
let { url, email, password } = this.jingrowSite;
return {
url: 'jcloud.api.site.get_backup_links',
params: {
url,
email,
password
},
validate() {
let { url, email, password } = this.jingrowSite;
if (!(url && email && password)) {
return 'Please enter URL, Username and Password';
}
},
onSuccess(remoteFiles) {
let selectedFiles = {};
for (let file of remoteFiles) {
selectedFiles[file.type] = file.remote_file;
}
this.$emit('update:selectedFiles', selectedFiles);
}
};
}
},
methods: {
showAlert() {
this.manualMigration = true;
},
errorContains(word) {
return (
this.$resources.getBackupLinks.error &&
this.$resources.getBackupLinks.error.search(word) !== -1
);
}
},
computed: {
fetchedBackupFiles() {
if (!this.$resources.getBackupLinks.data) {
return [];
}
return this.$resources.getBackupLinks.data.map(file => {
// Convert "20200820_124804-jerpcom-private-files.tar" to "20200820T124804"
// so DateTime can parse it
let timestamp_string = file.file_name
.split('-')[0]
.split('_')
.join('T');
let formatted = DateTime.fromISO(timestamp_string).toLocaleString(
DateTime.DATETIME_FULL
);
return {
...file,
timestamp: formatted
};
});
}
},
watch: {
wantToSkipFailingPatches(value) {
this.$emit('update:skipFailingPatches', value);
}
}
};
</script>