blob: f547737b2810096eaf75cad26de05c394f324885 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
<template>
<div>
<a-card class="breadcrumb-card">
<a-row>
<a-col :span="24" style="padding-left: 12px">
<a-breadcrumb :routes="getRoutes()">
<template #itemRender="{ route }">
<span v-if="['/', ''].includes(route.path) && route.breadcrumbName === 'root'">
<a @click="openDir('')">
<home-outlined/>
</a>
</span>
<span v-else>
<a @click="openDir(route.path)">
{{ route.breadcrumbName }}
</a>
</span>
</template>
</a-breadcrumb>
</a-col>
<a-col>
<a-tooltip placement="bottom">
<template #title>{{ $t('label.refresh') }}</template>
<a-button
style="margin-top: 4px"
:loading="loading"
shape="round"
size="small"
@click="fetchData()"
>
<template #icon><ReloadOutlined /></template>
{{ $t('label.refresh') }}
</a-button>
</a-tooltip>
</a-col>
</a-row>
</a-card>
<a-modal
:title="$t('message.data.migration')"
:visible="showMigrateModal"
:maskClosable="true"
:confirmLoading="migrateModalLoading"
@cancel="showMigrateModal = false"
:footer="null"
width="50%"
:okText="$t('label.ok')"
:cancelText="$t('label.cancel')">
<div>
<migrate-image-store-resource
:sourceImageStore="resource"
:templateIdsToMigrate="templateIdsToMigrate"
:snapshotIdsToMigrate="snapshotIdsToMigrate"
@close-action="showMigrateModal = false"
/>
</div>
</a-modal>
<div>
<a-table
:columns="columns"
:row-key="record => record.name"
:data-source="dataSource"
:pagination="{ current: page, pageSize: pageSize, total: total }"
@change="handleTableChange">
<template #bodyCell="{ column, record }">
<template v-if="column.key == 'name'">
<template v-if="record.isdirectory">
<a @click="openDir(`${this.browserPath}${record.name}/`)">
<folder-outlined /> {{ record.name }}
</a>
</template>
<template v-else-if="resourceType === 'ImageStore'">
<a @click="downloadFile(record)">
<template v-if="record.snapshotid">
<build-outlined/>
</template>
<template v-else-if="record.volumeid">
<hdd-outlined/>
</template>
<template v-else-if="record.templateid">
<usb-outlined v-if="record.format === 'ISO'"/>
<save-outlined v-else />
</template>
{{ record.name }}
</a>
</template>
<template v-else>
<template v-if="record.snapshotid">
<build-outlined/>
</template>
<template v-else-if="record.volumeid">
<hdd-outlined/>
</template>
<template v-else-if="record.templateid">
<usb-outlined v-if="record.format === 'ISO'"/>
<save-outlined v-else />
</template>
{{ record.name }}
</template>
</template>
<template v-if="column.key == 'size'">
<template v-if="!record.isdirectory">
{{ convertBytes(record.size) }}
</template>
</template>
<template v-if="column.key == 'lastupdated'">
{{ $toLocaleDate(record.lastupdated) }}
</template>
<template v-if="column.key == 'associatedResource'">
<template v-if="record.snapshotid">
<router-link :to="{ path: '/snapshot/' + record.snapshotid }" target='_blank' >
{{ record.snapshotname }}
</router-link>
</template>
<template v-else-if="record.volumeid">
<router-link :to="{ path: '/volume/' + record.volumeid }" target='_blank' >
{{ record.volumename }}
</router-link>
</template>
<template v-else-if="record.templateid">
<router-link v-if="record.format === 'ISO'" :to="{ path: '/iso/' + record.templateid }" target='_blank' >
{{ record.templatename }}
</router-link>
<router-link v-else :to="{ path: '/template/' + record.templateid }" target='_blank'>
{{ record.templatename }}
</router-link>
</template>
<template v-else>
{{ $t('label.unknown') }}
</template>
</template>
<template v-else-if="column.key === 'actions' && (record.templateid || record.snapshotid)">
<tooltip-button
tooltipPlacement="top"
:tooltip="$t('label.migrate.data.from.image.store')"
icon="arrows-alt-outlined"
:copyResource="String(resource.id)"
@onClick="openMigrationModal(record)" />
</template>
</template>
</a-table>
</div>
</div>
</template>
<script>
import { api } from '@/api'
import InfoCard from '@/components/view/InfoCard'
import TooltipButton from '@/components/widgets/TooltipButton'
import MigrateImageStoreResource from '@/views/storage/MigrateImageStoreResource'
export default {
name: 'StorageBrowser',
components: {
InfoCard,
MigrateImageStoreResource,
TooltipButton
},
props: {
resource: {
type: Object,
required: true
},
resourceType: {
type: String,
required: true
}
},
data () {
var columns = [
{
key: 'name',
title: this.$t('label.name')
},
{
key: 'size',
title: this.$t('label.size')
},
{
key: 'lastupdated',
title: this.$t('label.last.updated')
},
{
key: 'associatedResource',
title: this.$t('label.associated.resource')
}
]
if (this.resourceType === 'ImageStore') {
columns.push({
key: 'actions',
title: this.$t('label.actions')
})
}
return {
loading: false,
dataSource: [],
browserPath: this.$route.query.browserPath || '',
page: parseInt(this.$route.query.browserPage) || 1,
pageSize: parseInt(this.$route.query.browserPageSize) || 10,
total: 0,
columns: columns,
migrateModalLoading: false,
showMigrateModal: false,
templateIdsToMigrate: [],
snapshotIdsToMigrate: []
}
},
created () {
this.fetchData()
},
methods: {
openMigrationModal (record) {
if (record.snapshotid) {
this.snapshotIdsToMigrate.push(record.snapshotid)
} else if (record.templateid) {
this.templateIdsToMigrate.push(record.templateid)
}
this.showMigrateModal = true
},
handleTableChange (pagination, filters, sorter) {
this.page = pagination.current
this.pageSize = pagination.pageSize
this.fetchData()
},
fetchImageStoreObjects () {
this.loading = true
api('listImageStoreObjects', {
path: this.browserPath,
id: this.resource.id,
page: this.page,
pagesize: this.pageSize
}).then(json => {
this.dataSource = json.listimagestoreobjectsresponse.datastoreobject
this.total = json.listimagestoreobjectsresponse.count
}).finally(() => {
this.loading = false
})
},
fetchPrimaryStoreObjects () {
this.loading = true
api('listStoragePoolObjects', {
path: this.browserPath,
id: this.resource.id,
page: this.page,
pagesize: this.pageSize
}).then(json => {
this.dataSource = json.liststoragepoolobjectsresponse.datastoreobject
this.total = json.liststoragepoolobjectsresponse.count
}).finally(() => {
this.loading = false
})
},
fetchData () {
this.dataSource = []
this.$router.replace(
{
path: this.$route.path,
query: {
...this.$route.query,
browserPath: this.browserPath,
browserPage: this.page,
browserPageSize: this.browserPageSize
}
}
)
if (this.resourceType === 'ImageStore') {
this.fetchImageStoreObjects()
} else if (this.resourceType === 'PrimaryStorage') {
this.fetchPrimaryStoreObjects()
}
},
getRoutes () {
let path = ''
const routeList = [{
path: path,
breadcrumbName: 'root'
}]
for (const route of this.browserPath.split('/')) {
if (route) {
path = `${path}${route}/`
routeList.push({
path: path,
breadcrumbName: route
})
}
}
return routeList
},
convertBytes (val) {
if (val < 1024 * 1024) return `${(val / 1024).toFixed(2)} KB`
if (val < 1024 * 1024 * 1024) return `${(val / 1024 / 1024).toFixed(2)} MB`
if (val < 1024 * 1024 * 1024 * 1024) return `${(val / 1024 / 1024 / 1024).toFixed(2)} GB`
if (val < 1024 * 1024 * 1024 * 1024 * 1024) return `${(val / 1024 / 1024 / 1024 / 1024).toFixed(2)} TB`
return val
},
openDir (name) {
this.browserPath = name
this.page = 1
this.pageSize = 10
this.fetchData()
},
downloadFile (record) {
this.loading = true
const params = {
id: this.resource.id,
path: `${this.browserPath}${record.name}`
}
api('downloadImageStoreObject', params).then(response => {
const jobId = response.downloadimagestoreobjectresponse.jobid
this.$pollJob({
jobId: jobId,
successMethod: (result) => {
const url = result.jobresult.downloadimagestoreobjectresponse.url
const name = result.jobresult.downloadimagestoreobjectresponse.name
var elem = window.document.createElement('a')
elem.setAttribute('href', new URL(url))
elem.setAttribute('download', name)
elem.setAttribute('target', '_blank')
document.body.appendChild(elem)
elem.click()
document.body.removeChild(elem)
this.loading = false
},
errorMethod: () => {
this.loading = false
},
catchMessage: this.$t('error.fetching.async.job.result'),
catchMethod: () => {
this.loading = false
}
})
}).catch(error => {
console.error(error)
this.$message.error(error)
this.loading = false
})
}
}
}
</script>