You've already forked AstralRinth
forked from didirus/AstralRinth
This reverts commit b11934054d.
This commit is contained in:
@@ -13,23 +13,14 @@ import {
|
|||||||
TrashIcon,
|
TrashIcon,
|
||||||
XIcon,
|
XIcon,
|
||||||
} from '@modrinth/assets'
|
} from '@modrinth/assets'
|
||||||
import {
|
import { ButtonStyled, commonMessages, OverflowMenu, ProgressBar } from '@modrinth/ui'
|
||||||
ButtonStyled,
|
|
||||||
commonMessages,
|
|
||||||
injectNotificationManager,
|
|
||||||
OverflowMenu,
|
|
||||||
ProgressBar,
|
|
||||||
} from '@modrinth/ui'
|
|
||||||
import type { Backup } from '@modrinth/utils'
|
import type { Backup } from '@modrinth/utils'
|
||||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { computed, ref } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import type { ModrinthServer } from '~/composables/servers/modrinth-servers.ts'
|
|
||||||
|
|
||||||
const flags = useFeatureFlags()
|
const flags = useFeatureFlags()
|
||||||
const { formatMessage } = useVIntl()
|
const { formatMessage } = useVIntl()
|
||||||
const { addNotification } = injectNotificationManager()
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'download' | 'rename' | 'restore' | 'lock' | 'retry'): void
|
(e: 'download' | 'rename' | 'restore' | 'lock' | 'retry'): void
|
||||||
@@ -42,13 +33,11 @@ const props = withDefaults(
|
|||||||
preview?: boolean
|
preview?: boolean
|
||||||
kyrosUrl?: string
|
kyrosUrl?: string
|
||||||
jwt?: string
|
jwt?: string
|
||||||
server?: ModrinthServer
|
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
preview: false,
|
preview: false,
|
||||||
kyrosUrl: undefined,
|
kyrosUrl: undefined,
|
||||||
jwt: undefined,
|
jwt: undefined,
|
||||||
server: undefined,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -135,48 +124,7 @@ const messages = defineMessages({
|
|||||||
id: 'servers.backups.item.retry',
|
id: 'servers.backups.item.retry',
|
||||||
defaultMessage: 'Retry',
|
defaultMessage: 'Retry',
|
||||||
},
|
},
|
||||||
downloadingBackup: {
|
|
||||||
id: 'servers.backups.item.downloading-backup',
|
|
||||||
defaultMessage: 'Downloading backup...',
|
|
||||||
},
|
|
||||||
downloading: {
|
|
||||||
id: 'servers.backups.item.downloading',
|
|
||||||
defaultMessage: 'Downloading',
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const downloadingState = ref<{ progress: number; state: string } | undefined>(undefined)
|
|
||||||
|
|
||||||
const downloading = computed(() => downloadingState.value)
|
|
||||||
|
|
||||||
const handleDownload = async () => {
|
|
||||||
if (!props.server?.backups || downloading.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadingState.value = { progress: 0, state: 'ongoing' }
|
|
||||||
|
|
||||||
try {
|
|
||||||
const download = props.server.backups.downloadBackup(props.backup.id, props.backup.name)
|
|
||||||
|
|
||||||
download.onProgress((p) => {
|
|
||||||
downloadingState.value = { progress: p.progress, state: 'ongoing' }
|
|
||||||
})
|
|
||||||
|
|
||||||
await download.promise
|
|
||||||
|
|
||||||
emit('download')
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to download backup:', error)
|
|
||||||
addNotification({
|
|
||||||
type: 'error',
|
|
||||||
title: 'Download failed',
|
|
||||||
text: error instanceof Error ? error.message : 'Failed to download backup',
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
downloadingState.value = undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
@@ -244,15 +192,6 @@ const handleDownload = async () => {
|
|||||||
class="max-w-full"
|
class="max-w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="downloading" class="col-span-2 flex flex-col gap-3 text-blue">
|
|
||||||
{{ formatMessage(messages.downloadingBackup) }}
|
|
||||||
<ProgressBar
|
|
||||||
:progress="downloading.progress >= 0 ? downloading.progress : 0"
|
|
||||||
color="blue"
|
|
||||||
:waiting="downloading.progress <= 0"
|
|
||||||
class="max-w-full"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="col-span-2">
|
<div class="col-span-2">
|
||||||
{{ dayjs(backup.created_at).format('MMMM D, YYYY [at] h:mm A') }}
|
{{ dayjs(backup.created_at).format('MMMM D, YYYY [at] h:mm A') }}
|
||||||
@@ -284,32 +223,34 @@ const handleDownload = async () => {
|
|||||||
</button>
|
</button>
|
||||||
</ButtonStyled>
|
</ButtonStyled>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<ButtonStyled v-show="!downloading">
|
<ButtonStyled>
|
||||||
<button :disabled="!server?.backups" @click="handleDownload">
|
<a
|
||||||
|
:class="{
|
||||||
|
disabled: !kyrosUrl || !jwt,
|
||||||
|
}"
|
||||||
|
:href="`https://${kyrosUrl}/modrinth/v0/backups/${backup.id}/download?auth=${jwt}`"
|
||||||
|
@click="() => emit('download')"
|
||||||
|
>
|
||||||
<DownloadIcon />
|
<DownloadIcon />
|
||||||
{{ formatMessage(commonMessages.downloadButton) }}
|
{{ formatMessage(commonMessages.downloadButton) }}
|
||||||
</button>
|
</a>
|
||||||
</ButtonStyled>
|
</ButtonStyled>
|
||||||
<ButtonStyled circular type="transparent">
|
<ButtonStyled circular type="transparent">
|
||||||
<OverflowMenu
|
<OverflowMenu
|
||||||
:options="[
|
:options="[
|
||||||
{
|
{ id: 'rename', action: () => emit('rename') },
|
||||||
id: 'rename',
|
|
||||||
action: () => emit('rename'),
|
|
||||||
disabled: !!restoring || !!downloading,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'restore',
|
id: 'restore',
|
||||||
action: () => emit('restore'),
|
action: () => emit('restore'),
|
||||||
disabled: !!restoring || !!downloading,
|
disabled: !!restoring,
|
||||||
},
|
},
|
||||||
{ id: 'lock', action: () => emit('lock'), disabled: !!restoring || !!downloading },
|
{ id: 'lock', action: () => emit('lock') },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{
|
{
|
||||||
id: 'delete',
|
id: 'delete',
|
||||||
color: 'red',
|
color: 'red',
|
||||||
action: () => emit('delete'),
|
action: () => emit('delete'),
|
||||||
disabled: !!restoring || !!downloading,
|
disabled: !!restoring,
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -106,87 +106,4 @@ export class BackupsModule extends ServerModule {
|
|||||||
async getAutoBackup(): Promise<AutoBackupSettings> {
|
async getAutoBackup(): Promise<AutoBackupSettings> {
|
||||||
return await useServersFetch(`servers/${this.serverId}/autobackup`)
|
return await useServersFetch(`servers/${this.serverId}/autobackup`)
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadBackup(
|
|
||||||
backupId: string,
|
|
||||||
backupName: string,
|
|
||||||
): {
|
|
||||||
promise: Promise<void>
|
|
||||||
onProgress: (cb: (p: { loaded: number; total: number; progress: number }) => void) => void
|
|
||||||
cancel: () => void
|
|
||||||
} {
|
|
||||||
const progressSubject = new EventTarget()
|
|
||||||
const abortController = new AbortController()
|
|
||||||
|
|
||||||
const downloadPromise = new Promise<void>((resolve, reject) => {
|
|
||||||
const auth = this.server.general?.node
|
|
||||||
if (!auth?.instance || !auth?.token) {
|
|
||||||
reject(new Error('Missing authentication credentials'))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest()
|
|
||||||
|
|
||||||
xhr.addEventListener('progress', (e) => {
|
|
||||||
if (e.lengthComputable) {
|
|
||||||
const progress = e.loaded / e.total
|
|
||||||
progressSubject.dispatchEvent(
|
|
||||||
new CustomEvent('progress', {
|
|
||||||
detail: { loaded: e.loaded, total: e.total, progress },
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// progress = -1 to indicate indeterminate size
|
|
||||||
progressSubject.dispatchEvent(
|
|
||||||
new CustomEvent('progress', {
|
|
||||||
detail: { loaded: e.loaded, total: 0, progress: -1 },
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
xhr.onload = () => {
|
|
||||||
if (xhr.status >= 200 && xhr.status < 300) {
|
|
||||||
try {
|
|
||||||
const blob = xhr.response
|
|
||||||
const url = window.URL.createObjectURL(blob)
|
|
||||||
const a = document.createElement('a')
|
|
||||||
a.href = url
|
|
||||||
a.download = `${backupName}.zip`
|
|
||||||
document.body.appendChild(a)
|
|
||||||
a.click()
|
|
||||||
document.body.removeChild(a)
|
|
||||||
window.URL.revokeObjectURL(url)
|
|
||||||
resolve()
|
|
||||||
} catch (error) {
|
|
||||||
reject(error)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reject(new Error(`Download failed with status ${xhr.status}`))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xhr.onerror = () => reject(new Error('Download failed'))
|
|
||||||
xhr.onabort = () => reject(new Error('Download cancelled'))
|
|
||||||
|
|
||||||
xhr.open(
|
|
||||||
'GET',
|
|
||||||
`https://${auth.instance}/modrinth/v0/backups/${backupId}/download?auth=${auth.token}`,
|
|
||||||
)
|
|
||||||
xhr.responseType = 'blob'
|
|
||||||
xhr.send()
|
|
||||||
|
|
||||||
abortController.signal.addEventListener('abort', () => xhr.abort())
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
promise: downloadPromise,
|
|
||||||
onProgress: (cb: (p: { loaded: number; total: number; progress: number }) => void) => {
|
|
||||||
progressSubject.addEventListener('progress', ((e: CustomEvent) => {
|
|
||||||
cb(e.detail)
|
|
||||||
}) as EventListener)
|
|
||||||
},
|
|
||||||
cancel: () => abortController.abort(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2570,12 +2570,6 @@
|
|||||||
"servers.backups.item.creating-backup": {
|
"servers.backups.item.creating-backup": {
|
||||||
"message": "Creating backup..."
|
"message": "Creating backup..."
|
||||||
},
|
},
|
||||||
"servers.backups.item.downloading": {
|
|
||||||
"message": "Downloading"
|
|
||||||
},
|
|
||||||
"servers.backups.item.downloading-backup": {
|
|
||||||
"message": "Downloading backup..."
|
|
||||||
},
|
|
||||||
"servers.backups.item.failed-to-create-backup": {
|
"servers.backups.item.failed-to-create-backup": {
|
||||||
"message": "Failed to create backup"
|
"message": "Failed to create backup"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -105,7 +105,6 @@
|
|||||||
v-for="backup in backups"
|
v-for="backup in backups"
|
||||||
:key="`backup-${backup.id}`"
|
:key="`backup-${backup.id}`"
|
||||||
:backup="backup"
|
:backup="backup"
|
||||||
:server="props.server"
|
|
||||||
:kyros-url="props.server.general?.node.instance"
|
:kyros-url="props.server.general?.node.instance"
|
||||||
:jwt="props.server.general?.node.token"
|
:jwt="props.server.general?.node.token"
|
||||||
@download="() => triggerDownloadAnimation()"
|
@download="() => triggerDownloadAnimation()"
|
||||||
|
|||||||
Reference in New Issue
Block a user