fix: support cancelling chunk uploads (#13233)

* fix: support cancelling chunk uploads

* fix: validate chunk upload filenames
This commit is contained in:
ssongliu
2026-07-10 15:46:59 +08:00
committed by GitHub
parent f1372dda85
commit 1fd62fbaf7
15 changed files with 189 additions and 367 deletions
+69 -2
View File
@@ -12,7 +12,9 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
"time"
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
"github.com/1Panel-dev/1Panel/agent/app/dto"
@@ -28,6 +30,11 @@ import (
qrcode "github.com/skip2/go-qrcode"
)
var cancelledChunkUploads = struct {
sync.RWMutex
ids map[string]struct{}
}{ids: make(map[string]struct{})}
// @Tags File
// @Summary List files
// @Accept json
@@ -873,7 +880,24 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
}
}
filename := c.PostForm("filename")
fileDir := filepath.Join(tmpDir, filename)
if filename == "" || filepath.Base(filename) != filename || strings.ContainsAny(filename, `/\\`) {
helper.BadRequest(c, errors.New("invalid filename"))
return
}
uploadID := strings.TrimSpace(c.PostForm("uploadID"))
cancellable := uploadID != ""
if cancellable && (filepath.Base(uploadID) != uploadID || strings.ContainsAny(uploadID, `/\\`)) {
helper.BadRequest(c, errors.New("invalid upload ID"))
return
}
if !cancellable {
uploadID = filename
}
fileDir := filepath.Join(tmpDir, uploadID)
if cancellable && chunkUploadCancelled(uploadID) {
helper.BadRequest(c, errors.New("upload cancelled"))
return
}
if chunkIndex == 0 {
if fileOp.Stat(fileDir) {
_ = fileOp.DeleteDir(fileDir)
@@ -884,7 +908,7 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
defer func() {
if err != nil {
_ = os.Remove(fileDir)
_ = os.RemoveAll(fileDir)
}
}()
var (
@@ -904,6 +928,11 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
helper.InternalServer(c, buserr.WithMap("ErrFileUpload", map[string]interface{}{"name": filename, "detail": err.Error()}, err))
return
}
if cancellable && chunkUploadCancelled(uploadID) {
err = errors.New("upload cancelled")
helper.BadRequest(c, err)
return
}
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", filename, chunkIndex))
err = os.WriteFile(chunkPath, chunkData, constant.DirPerm)
@@ -922,12 +951,50 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
helper.InternalServer(c, buserr.WithMap("ErrFileUpload", map[string]interface{}{"name": filename, "detail": err.Error()}, err))
return
}
if cancellable {
cancelledChunkUploads.Lock()
delete(cancelledChunkUploads.ids, uploadID)
cancelledChunkUploads.Unlock()
}
helper.SuccessWithData(c, true)
} else {
return
}
}
// StopChunkUpload removes temporary chunks left by a cancelled upload.
func (b *BaseApi) StopChunkUpload(c *gin.Context) {
var req request.FileProcessReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
uploadID := strings.TrimSpace(req.Key)
if uploadID == "" || filepath.Base(uploadID) != uploadID || strings.ContainsAny(uploadID, `/\\`) {
helper.BadRequest(c, errors.New("invalid upload ID"))
return
}
cancelledChunkUploads.Lock()
cancelledChunkUploads.ids[uploadID] = struct{}{}
cancelledChunkUploads.Unlock()
time.AfterFunc(10*time.Minute, func() {
cancelledChunkUploads.Lock()
delete(cancelledChunkUploads.ids, uploadID)
cancelledChunkUploads.Unlock()
})
if err := os.RemoveAll(filepath.Join(global.Dir.TmpDir, "upload", uploadID)); err != nil {
helper.InternalServer(c, err)
return
}
helper.Success(c)
}
func chunkUploadCancelled(uploadID string) bool {
cancelledChunkUploads.RLock()
_, ok := cancelledChunkUploads.ids[uploadID]
cancelledChunkUploads.RUnlock()
return ok
}
var wsUpgrade = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
+1
View File
@@ -39,6 +39,7 @@ func (f *FileRouter) InitRouter(Router *gin.RouterGroup) {
fileRouter.POST("/batch/check", baseApi.BatchCheckFiles)
fileRouter.POST("/upload", baseApi.UploadFiles)
fileRouter.POST("/chunkupload", baseApi.UploadChunkFiles)
fileRouter.POST("/chunkupload/stop", baseApi.StopChunkUpload)
fileRouter.POST("/rename", baseApi.ChangeFileName)
fileRouter.POST("/wget", baseApi.WgetFile)
fileRouter.POST("/wget/stop", baseApi.StopWget)
+4
View File
@@ -125,6 +125,10 @@ export const chunkUploadFileData = (params: FormData, config: AxiosRequestConfig
return http.upload<File.File>('files/chunkupload', params, config);
};
export const stopChunkUpload = (key: string) => {
return http.post('files/chunkupload/stop', { key });
};
export const renameRile = (params: File.FileRename) => {
return http.post<File.File>('files/rename', params);
};
+8 -34
View File
@@ -5661,15 +5661,12 @@ const message = {
dependencies: 'Dependencies',
dependencyPurpose: 'Purpose',
dependencyPurposeMap: {
kvm: 'Provides hardware virtualization support for accelerated VM execution.',
libvirt: 'Provides VM management services for lifecycle control and resource scheduling.',
storage: 'Provides the default storage directory or pool for VM disk files.',
},
dependencyNotReady: 'VM dependency checks failed. Fix the dependencies before using virtual machines.',
helperUnavailable:
'VM capability initialization failed. Check core logs or upgrade again before using VMs.',
helperNotStart:
'The VM runtime environment is not ready. Fix the host virtualization service before using VMs.',
kvmUnavailable: 'No available KVM hardware virtualization capability was detected.',
kvmCheckCpu: 'Confirm that the host CPU supports Intel VT-x or AMD-V virtualization.',
kvmCheckBios: 'Enable virtualization options in BIOS/UEFI.',
@@ -5679,7 +5676,6 @@ const message = {
cpu: 'CPU',
memory: 'Memory',
disk: 'Disk',
totalVM: 'Total VMs',
abnormal: 'Abnormal',
resourceOverview: 'Resource Overview',
cpuAllocated: 'CPU Allocated',
@@ -5687,14 +5683,10 @@ const message = {
storageUsed: 'Storage Used',
riskReminder: 'Risk Reminders',
noRisk: 'No risks',
quickEntry: 'Quick Entry',
runtimeHealth: 'Runtime Health',
runtimeReady: 'VM runtime is ready',
runtimeAbnormal: 'VM runtime is abnormal',
environmentCheck: 'Environment Check',
noDependency: 'No dependency check data',
storageOverview: 'Storage Overview',
recentVM: 'Recent VMs',
totalAllocated: 'Calculated by total VM configuration',
runningAllocated: 'Running allocation: {0}',
storageAvailable: 'Available: {0}',
@@ -5713,22 +5705,15 @@ const message = {
storageLimitHelper: 'Current free space in the target storage pool: {0}',
storageLimitExceeded: 'Disk capacity exceeds the limit. Current maximum available: {0}.',
iso: 'ISO',
createSource: 'Create Source',
createFromTemplate: 'Create from template',
blankDisk: 'Blank Disk',
template: 'Template',
templateName: 'Template Name',
convertToTemplate: 'Convert to Template',
sourceVM: 'Source VM',
templateSize: 'Template Size',
deleteTemplate: 'Delete Template',
deleteTemplateConfirm: 'Delete template {0}. This operation cannot be rolled back. Continue?',
diskSize: 'Disk Size',
diskPath: 'Disk Path',
diskPathHelper:
'Optional. If empty, the system creates <VM name>.qcow2 in the selected storage pool directory. Custom values must be absolute paths.',
imagePath: 'Image Path',
imagePathHelper: 'Optional. If set, use an existing qcow2 image absolute path.',
isoPath: 'ISO Path',
storagePool: 'Storage Pool',
network: 'Network',
@@ -5745,8 +5730,10 @@ const message = {
dhcpStart: 'DHCP Start',
dhcpEnd: 'DHCP End',
bootOrder: 'Boot Order',
bootOrderHelper:
'HD boots from disk first and then tries the ISO if the disk is not bootable. CD-ROM boots from ISO first.',
bootDiskFirst: 'Disk first (HD CD-ROM)',
bootIsoFirst: 'ISO first (CD-ROM HD)',
bootOrderConfirm:
'Change the boot order to {0}? The VM will try currently mounted, bootable devices in this order the next time it starts.',
startAfterCreate: 'Start after creation',
autoStart: 'Autostart',
resourceAutoStart: 'Autostart',
@@ -5754,16 +5741,6 @@ const message = {
available: 'Available',
vmCount: 'Linked VMs',
usedIPs: 'Used IPs',
syncFromServer: 'Sync from Server',
notFound: 'Not found',
resourceStatus: {
running: 'Running',
inactive: 'Inactive',
building: 'Building',
degraded: 'Degraded',
inaccessible: 'Inaccessible',
unknown: 'Unknown',
},
monitor: 'Monitor',
monitorNotReady: 'The virtual machine is not running. Monitoring data is unavailable.',
monitorLoadFailed: 'Failed to get VM monitoring data.',
@@ -5790,10 +5767,11 @@ const message = {
snapshot: 'Snapshot',
createSnapshot: 'Create Snapshot',
recoverSnapshot: 'Recover Snapshot',
snapshotName: 'Snapshot Name',
snapshotSize: 'Snapshot Size',
snapshotSize: 'Usage',
currentSnapshot: 'Current',
snapshotEmpty: 'No snapshots',
snapshotOperationHelper:
'The current snapshot cannot be deleted. Snapshots can be recovered only when the virtual machine is shut off.',
snapshotRecoverConfirm:
'Recover virtual machine [{1}] to snapshot [{0}]? The VM disk will be restored to the snapshot state.',
interface: 'Network Interface',
@@ -5814,11 +5792,7 @@ const message = {
downloadFromServer: 'Download from Server',
isoTargetDir: 'ISO Target Path',
isoTargetDirHelper: 'ISO files uploaded locally or downloaded from the server are saved to this directory.',
isoTargetDirOptional: 'No ISO target path is set. The original ISO source path will be used.',
isoTargetDirAvailable: 'The ISO target path is available.',
isoTargetDirUnavailable: 'The ISO target path must be inside an available VM storage pool.',
isoTargetDirCheckRequired: 'Check the ISO target path before saving.',
checkPath: 'Check',
addingIsoRecord: 'Adding ISO record',
isoSize: 'ISO Size',
deleteIsoConfirm: 'This delete operation cannot be rolled back. Continue?',
deleteSourceFile: 'Delete source file',
+8 -30
View File
@@ -5707,7 +5707,6 @@ const message = {
dependencies: 'Dependencias',
dependencyPurpose: 'Propósito',
dependencyPurposeMap: {
kvm: 'Proporciona virtualización por hardware para acelerar la ejecución de las VM.',
libvirt: 'Proporciona servicios de gestión de VM para el ciclo de vida y la planificación de recursos.',
storage:
'Proporciona el directorio o pool de almacenamiento predeterminado para los archivos de disco de la VM.',
@@ -5716,8 +5715,6 @@ const message = {
'Las comprobaciones de dependencias de la VM han fallado. Corrija las dependencias antes de usar máquinas virtuales.',
helperUnavailable:
'La inicialización de la capacidad de VM falló. Revise los registros de Core o actualice de nuevo antes de usar máquinas virtuales.',
helperNotStart:
'El servicio de VM no se está ejecutando. Inicie el servicio antes de usar máquinas virtuales.',
cpu: 'CPU',
memory: 'Memoria',
disk: 'Disco',
@@ -5728,22 +5725,15 @@ const message = {
storageLimitHelper: 'Espacio libre actual en el pool de almacenamiento de destino: {0}',
storageLimitExceeded: 'La capacidad del disco supera el límite. Máximo disponible actual: {0}.',
iso: 'ISO',
createSource: 'Origen de creación',
createFromTemplate: 'Crear desde plantilla',
blankDisk: 'Blank Disk',
template: 'Template',
templateName: 'Template Name',
convertToTemplate: 'Convert to Template',
sourceVM: 'Source VM',
templateSize: 'Template Size',
deleteTemplate: 'Delete Template',
deleteTemplateConfirm: 'Eliminar plantilla {0}. Esta operación no se puede revertir. ¿Continuar?',
diskSize: 'Tamaño del disco',
diskPath: 'Ruta del disco',
diskPathHelper:
'Opcional. Si está vacío, el sistema crea <nombre de VM>.qcow2 en el directorio del pool de almacenamiento seleccionado. Los valores personalizados deben ser rutas absolutas.',
imagePath: 'Ruta de la imagen',
imagePathHelper: 'Opcional. Si se define, use la ruta absoluta de una imagen qcow2 existente.',
isoPath: 'Ruta ISO',
storagePool: 'Pool de almacenamiento',
network: 'Red',
@@ -5760,8 +5750,10 @@ const message = {
dhcpStart: 'Inicio DHCP',
dhcpEnd: 'Fin DHCP',
bootOrder: 'Orden de arranque',
bootOrderHelper:
'HD arranca primero desde el disco y prueba el ISO si el disco no es arrancable. CD-ROM arranca primero desde el ISO.',
bootDiskFirst: 'Disco primero (HD CD-ROM)',
bootIsoFirst: 'ISO primero (CD-ROM HD)',
bootOrderConfirm:
'¿Cambiar el orden de arranque a {0}? La próxima vez que se inicie, la VM probará en este orden los dispositivos arrancables que estén montados.',
startAfterCreate: 'Iniciar después de crear',
autoStart: 'Inicio automático',
resourceAutoStart: 'Inicio automático',
@@ -5769,16 +5761,6 @@ const message = {
available: 'Disponible',
vmCount: 'VM vinculadas',
usedIPs: 'IP usadas',
syncFromServer: 'Sincronizar desde servidor',
notFound: 'No encontrado',
resourceStatus: {
running: 'En ejecución',
inactive: 'Inactivo',
building: 'Creando',
degraded: 'Degradado',
inaccessible: 'Inaccesible',
unknown: 'Desconocido',
},
monitor: 'Monitor',
monitorNotReady: 'The virtual machine is not running. Monitoring data is unavailable.',
monitorLoadFailed: 'Failed to get VM monitoring data.',
@@ -5807,10 +5789,11 @@ const message = {
snapshot: 'Snapshot',
createSnapshot: 'Create Snapshot',
recoverSnapshot: 'Recover Snapshot',
snapshotName: 'Snapshot Name',
snapshotSize: 'Snapshot Size',
snapshotSize: 'Uso',
currentSnapshot: 'Current',
snapshotEmpty: 'No snapshots',
snapshotOperationHelper:
'La instantánea en uso no se puede eliminar. Las instantáneas solo se pueden restaurar cuando la máquina virtual está apagada.',
snapshotRecoverConfirm:
'Recover virtual machine [{1}] to snapshot [{0}]? The VM disk will be restored to the snapshot state.',
interface: 'Interfaz de red',
@@ -5832,12 +5815,7 @@ const message = {
isoTargetDir: 'Ruta de destino ISO',
isoTargetDirHelper:
'Los ISO cargados localmente o descargados desde el servidor se guardarán en este directorio.',
isoTargetDirOptional: 'No se definió una ruta de destino ISO. Se usará la ruta original del archivo ISO.',
isoTargetDirAvailable: 'La ruta de destino ISO está disponible.',
isoTargetDirUnavailable:
'La ruta de destino ISO debe estar dentro de un pool de almacenamiento de VM disponible.',
isoTargetDirCheckRequired: 'Compruebe la ruta de destino ISO antes de guardar.',
checkPath: 'Comprobar',
addingIsoRecord: 'Agregando registro ISO',
isoSize: 'Tamaño ISO',
deleteIsoConfirm: 'Esta operación de eliminación no se puede revertir. ¿Continuar?',
deleteSourceFile: 'Eliminar archivo de origen',
+8 -28
View File
@@ -5625,7 +5625,6 @@ const message = {
dependencies: 'وابستگی‌ها',
dependencyPurpose: 'کاربرد',
dependencyPurposeMap: {
kvm: 'قابلیت مجازی‌سازی سخت‌افزاری را فراهم می‌کند و پایه اجرای سریع ماشین مجازی است.',
libvirt: 'سرویس مدیریت ماشین مجازی را برای چرخه حیات و زمان‌بندی منابع فراهم می‌کند.',
storage: 'دایرکتوری یا استخر ذخیره‌سازی پیش‌فرض را برای فایل‌های دیسک ماشین مجازی فراهم می‌کند.',
},
@@ -5633,7 +5632,6 @@ const message = {
'بررسی وابستگی‌های ماشین مجازی موفق نبود. قبل از استفاده از ماشین مجازی، وابستگی‌ها را برطرف کنید.',
helperUnavailable:
'راه‌اندازی قابلیت ماشین مجازی ناموفق بود. لاگ Core را بررسی کنید یا دوباره ارتقاء دهید.',
helperNotStart: 'محیط اجرای ماشین مجازی آماده نیست. ابتدا سرویس مجازی‌سازی میزبان را برطرف کنید.',
cpu: 'CPU',
memory: 'حافظه',
disk: 'دیسک',
@@ -5644,22 +5642,15 @@ const message = {
storageLimitHelper: 'فضای آزاد فعلی در استخر ذخیره‌سازی مقصد: {0}',
storageLimitExceeded: 'ظرفیت دیسک از حد مجاز بیشتر است. حداکثر فعلی قابل استفاده: {0}.',
iso: 'ISO',
createSource: 'منبع ایجاد',
createFromTemplate: 'ایجاد از قالب',
blankDisk: 'دیسک خالی',
template: 'قالب',
templateName: 'نام قالب',
convertToTemplate: 'تبدیل به قالب',
sourceVM: 'ماشین مجازی منبع',
templateSize: 'اندازه قالب',
deleteTemplate: 'حذف قالب',
deleteTemplateConfirm: 'قالب {0} حذف شود؟ این عملیات قابل بازگشت نیست. ادامه می‌دهید؟',
diskSize: 'ظرفیت دیسک',
diskPath: 'مسیر دیسک',
diskPathHelper:
'اختیاری است. اگر خالی باشد، سیستم فایل نام-ماشین-مجازی.qcow2 را در مسیر استخر ذخیره‌سازی انتخاب‌شده ایجاد می‌کند. در صورت وارد کردن، باید مسیر مطلق باشد.',
imagePath: 'مسیر ایمیج',
imagePathHelper: 'اختیاری است. در صورت وارد کردن، باید مسیر مطلق یک ایمیج qcow2 موجود باشد.',
isoPath: 'مسیر ISO',
storagePool: 'استخر ذخیره‌سازی',
network: 'شبکه',
@@ -5676,8 +5667,10 @@ const message = {
dhcpStart: 'شروع DHCP',
dhcpEnd: 'پایان DHCP',
bootOrder: 'ترتیب بوت',
bootOrderHelper:
'HD یعنی ابتدا از دیسک بوت شود و اگر دیسک قابل بوت نبود ISO امتحان شود. CD-ROM یعنی ابتدا از ISO بوت شود.',
bootDiskFirst: 'ابتدا دیسک (HD CD-ROM)',
bootIsoFirst: 'ابتدا ISO (CD-ROM HD)',
bootOrderConfirm:
'ترتیب بوت به {0} تغییر کند؟ ماشین مجازی در راه‌اندازی بعدی، دستگاه‌های متصل و قابل بوت را به این ترتیب امتحان می‌کند.',
startAfterCreate: 'شروع پس از ایجاد',
autoStart: 'شروع خودکار',
resourceAutoStart: 'شروع خودکار',
@@ -5685,16 +5678,6 @@ const message = {
available: 'در دسترس',
vmCount: 'ماشین‌های مجازی مرتبط',
usedIPs: 'IPهای استفاده‌شده',
syncFromServer: 'همگام‌سازی از سرور',
notFound: 'وجود ندارد',
resourceStatus: {
running: 'در حال اجرا',
inactive: 'شروع نشده',
building: 'در حال ساخت',
degraded: 'تنزل‌یافته',
inaccessible: 'غیرقابل دسترس',
unknown: 'نامشخص',
},
monitor: 'مانیتورینگ',
monitorNotReady: 'ماشین مجازی در حال اجرا نیست و داده‌های مانیتورینگ در دسترس نیست.',
monitorLoadFailed: 'دریافت داده‌های مانیتورینگ ماشین مجازی ناموفق بود.',
@@ -5722,10 +5705,11 @@ const message = {
snapshot: 'اسنپ‌شات',
createSnapshot: 'ایجاد اسنپ‌شات',
recoverSnapshot: 'بازیابی اسنپ‌شات',
snapshotName: 'نام اسنپ‌شات',
snapshotSize: 'اندازه اسنپ‌شات',
snapshotSize: 'فضای مصرف‌شده',
currentSnapshot: 'فعلی',
snapshotEmpty: 'اسنپ‌شاتی وجود ندارد',
snapshotOperationHelper:
'اسنپ‌شات فعلی قابل حذف نیست؛ بازیابی اسنپ‌شات فقط زمانی مجاز است که ماشین مجازی خاموش باشد.',
snapshotRecoverConfirm:
'ماشین مجازی [{1}] به اسنپ‌شات [{0}] بازیابی شود؟ پس از بازیابی، دیسک ماشین مجازی به وضعیت آن اسنپ‌شات برمی‌گردد.',
interface: 'رابط شبکه',
@@ -5746,11 +5730,7 @@ const message = {
downloadFromServer: 'دانلود از سرور',
isoTargetDir: 'مسیر مقصد ISO',
isoTargetDirHelper: 'ISO های آپلودشده محلی یا دانلودشده از سرور در این دایرکتوری ذخیره می‌شوند.',
isoTargetDirOptional: 'مسیر مقصد ISO تنظیم نشده است. مسیر فایل منبع ISO اصلی استفاده خواهد شد.',
isoTargetDirAvailable: 'مسیر مقصد ISO قابل استفاده است.',
isoTargetDirUnavailable: 'مسیر مقصد ISO باید داخل یک استخر ذخیره‌سازی ماشین مجازی قابل استفاده باشد.',
isoTargetDirCheckRequired: 'قبل از ذخیره، مسیر مقصد ISO را بررسی کنید.',
checkPath: 'بررسی',
addingIsoRecord: 'در حال افزودن رکورد ISO',
isoSize: 'اندازه ISO',
deleteIsoConfirm: 'این عملیات حذف قابل بازگشت نیست. ادامه می‌دهید؟',
deleteSourceFile: 'حذف فایل منبع',
+8 -29
View File
@@ -5673,15 +5673,12 @@ const message = {
dependencies: '依存関係',
dependencyPurpose: '用途',
dependencyPurposeMap: {
kvm: 'ハードウェア仮想化機能を提供し仮想マシンを高速に実行する基盤です',
libvirt: '仮想マシン管理サービスを提供しライフサイクルとリソーススケジューリングを担当します',
storage: '仮想マシンのディスクファイルを保存するデフォルトの保存先またはストレージプールを提供します',
},
dependencyNotReady: '仮想マシンの依存関係チェックに失敗しました依存関係を処理してから使用してください',
helperUnavailable:
'仮想マシン機能の初期化に失敗しましたCore ログを確認するか再度アップグレードしてから使用してください',
helperNotStart:
'仮想マシンの実行環境が準備できていませんホストの仮想化サービスを処理してから使用してください',
cpu: 'CPU',
memory: 'メモリ',
disk: 'ディスク',
@@ -5692,22 +5689,15 @@ const message = {
storageLimitHelper: '対象ストレージプールの現在の空き容量{0}',
storageLimitExceeded: 'ディスク容量が上限を超えています現在利用可能な最大値{0}',
iso: 'ISO',
createSource: '作成元',
createFromTemplate: 'テンプレートから作成',
blankDisk: 'Blank Disk',
template: 'Template',
templateName: 'Template Name',
convertToTemplate: 'Convert to Template',
sourceVM: 'Source VM',
templateSize: 'Template Size',
deleteTemplate: 'Delete Template',
deleteTemplateConfirm: 'テンプレート {0} を削除しますこの操作は元に戻せません続行しますか',
diskSize: 'ディスク容量',
diskPath: 'ディスクパス',
diskPathHelper:
'空欄にできますシステムは選択したストレージプールディレクトリに 仮想マシン名.qcow2 を自動作成します入力する場合は絶対パスである必要があります',
imagePath: 'イメージパス',
imagePathHelper: '空欄にできます入力する場合は既存の qcow2 イメージの絶対パスを指定してください',
isoPath: 'ISO パス',
storagePool: 'ストレージプール',
network: 'ネットワーク',
@@ -5724,8 +5714,10 @@ const message = {
dhcpStart: 'DHCP 開始アドレス',
dhcpEnd: 'DHCP 終了アドレス',
bootOrder: '起動順序',
bootOrderHelper:
'HD はディスクから優先起動し起動できない場合に ISO を試しますCD-ROM ISO から優先起動します',
bootDiskFirst: 'ディスク優先HD CD-ROM',
bootIsoFirst: 'ISO 優先CD-ROM HD',
bootOrderConfirm:
'起動順序を {0} に変更しますか次回の起動時仮想マシンは現在接続されている起動可能なデバイスをこの順序で試します',
startAfterCreate: '作成後に起動',
autoStart: '自動起動',
resourceAutoStart: '自動起動',
@@ -5733,16 +5725,6 @@ const message = {
available: '利用可能',
vmCount: '関連 VM',
usedIPs: '使用済み IP',
syncFromServer: 'サーバーから同期',
notFound: '存在しません',
resourceStatus: {
running: '実行中',
inactive: '未起動',
building: '構築中',
degraded: '低下',
inaccessible: 'アクセス不可',
unknown: '不明',
},
monitor: 'Monitor',
monitorNotReady: 'The virtual machine is not running. Monitoring data is unavailable.',
monitorLoadFailed: 'Failed to get VM monitoring data.',
@@ -5771,10 +5753,11 @@ const message = {
snapshot: 'Snapshot',
createSnapshot: 'Create Snapshot',
recoverSnapshot: 'Recover Snapshot',
snapshotName: 'Snapshot Name',
snapshotSize: 'Snapshot Size',
snapshotSize: '使用量',
currentSnapshot: 'Current',
snapshotEmpty: 'No snapshots',
snapshotOperationHelper:
'現在使用中のスナップショットは削除できませんスナップショットは仮想マシンがシャットオフ状態の場合にのみ復元できます',
snapshotRecoverConfirm:
'Recover virtual machine [{1}] to snapshot [{0}]? The VM disk will be restored to the snapshot state.',
interface: 'ネットワークインターフェース',
@@ -5796,11 +5779,7 @@ const message = {
isoTargetDir: 'ISO ターゲットパス',
isoTargetDirHelper:
'ローカルアップロードまたはサーバーからダウンロードした ISO はこのディレクトリに保存されます',
isoTargetDirOptional: 'ISO ターゲットパスが設定されていないため元の ISO ソースファイルパスを使用します',
isoTargetDirAvailable: 'ISO ターゲットパスは利用可能です',
isoTargetDirUnavailable: 'ISO ターゲットパスは利用可能な仮想マシンストレージプール内である必要があります',
isoTargetDirCheckRequired: '保存前に ISO ターゲットパスを確認してください',
checkPath: '確認',
addingIsoRecord: 'ISO レコードを追加しています',
isoSize: 'ISO サイズ',
deleteIsoConfirm: 'この削除操作は元に戻せません続行しますか',
deleteSourceFile: '元ファイルを削除',
+8 -28
View File
@@ -5559,14 +5559,12 @@ const message = {
dependencies: '종속성',
dependencyPurpose: '용도',
dependencyPurposeMap: {
kvm: '하드웨어 가상화 기능을 제공하며 가상 머신 가속 실행의 기반입니다.',
libvirt: '가상 머신 관리 서비스를 제공하며 수명 주기와 리소스 스케줄링을 담당합니다.',
storage: '가상 머신 디스크 파일을 저장하기 위한 기본 저장소 디렉터리 또는 스토리지 풀을 제공합니다.',
},
dependencyNotReady: '가상 머신 종속성 검사를 통과하지 못했습니다. 종속성을 처리한 사용하세요.',
helperUnavailable:
'가상 머신 기능 초기화에 실패했습니다. Core 로그를 확인하거나 다시 업그레이드한 사용하세요.',
helperNotStart: '가상 머신 실행 환경이 준비되지 않았습니다. 호스트 가상화 서비스를 처리한 사용하세요.',
cpu: 'CPU',
memory: '메모리',
disk: '디스크',
@@ -5577,22 +5575,15 @@ const message = {
storageLimitHelper: '대상 스토리지 풀의 현재 사용 가능 공간: {0}',
storageLimitExceeded: '디스크 용량이 제한을 초과했습니다. 현재 최대 사용 가능: {0}.',
iso: 'ISO',
createSource: '생성 소스',
createFromTemplate: '템플릿에서 생성',
blankDisk: 'Blank Disk',
template: 'Template',
templateName: 'Template Name',
convertToTemplate: 'Convert to Template',
sourceVM: 'Source VM',
templateSize: 'Template Size',
deleteTemplate: 'Delete Template',
deleteTemplateConfirm: '템플릿 {0}() 삭제합니다. 작업은 되돌릴 없습니다. 계속하시겠습니까?',
diskSize: '디스크 용량',
diskPath: '디스크 경로',
diskPathHelper:
'비워둘 있습니다. 시스템은 선택한 스토리지 디렉터리에 가상머신이름.qcow2를 자동 생성합니다. 입력하는 경우 절대 경로여야 합니다.',
imagePath: '이미지 경로',
imagePathHelper: '비워둘 있습니다. 입력하는 경우 기존 qcow2 이미지의 절대 경로여야 합니다.',
isoPath: 'ISO 경로',
storagePool: '스토리지 ',
network: '네트워크',
@@ -5609,8 +5600,10 @@ const message = {
dhcpStart: 'DHCP 시작 주소',
dhcpEnd: 'DHCP 종료 주소',
bootOrder: '부팅 순서',
bootOrderHelper:
'HD는 디스크에서 먼저 부팅하고 디스크가 부팅 불가능하면 ISO를 시도합니다. CD-ROM은 ISO에서 먼저 부팅합니다.',
bootDiskFirst: '디스크 우선 (HD CD-ROM)',
bootIsoFirst: 'ISO 우선 (CD-ROM HD)',
bootOrderConfirm:
'부팅 순서를 {0}() 변경하시겠습니까? 다음 시작 가상 머신은 현재 연결된 부팅 가능한 장치를 순서대로 시도합니다.',
startAfterCreate: '생성 시작',
autoStart: '자동 시작',
resourceAutoStart: '자동 시작',
@@ -5618,16 +5611,6 @@ const message = {
available: '사용 가능',
vmCount: '연결된 VM',
usedIPs: '사용된 IP',
syncFromServer: '서버에서 동기화',
notFound: '존재하지 않음',
resourceStatus: {
running: '실행 ',
inactive: '시작되지 않음',
building: '빌드 ',
degraded: '저하됨',
inaccessible: '접근 불가',
unknown: ' 없음',
},
monitor: 'Monitor',
monitorNotReady: 'The virtual machine is not running. Monitoring data is unavailable.',
monitorLoadFailed: 'Failed to get VM monitoring data.',
@@ -5654,10 +5637,11 @@ const message = {
snapshot: 'Snapshot',
createSnapshot: 'Create Snapshot',
recoverSnapshot: 'Recover Snapshot',
snapshotName: 'Snapshot Name',
snapshotSize: 'Snapshot Size',
snapshotSize: '사용량',
currentSnapshot: 'Current',
snapshotEmpty: 'No snapshots',
snapshotOperationHelper:
'현재 사용 중인 스냅샷은 삭제할 없습니다. 가상 머신이 종료된 상태에서만 스냅샷을 복원할 있습니다.',
snapshotRecoverConfirm:
'Recover virtual machine [{1}] to snapshot [{0}]? The VM disk will be restored to the snapshot state.',
interface: '네트워크 인터페이스',
@@ -5678,11 +5662,7 @@ const message = {
downloadFromServer: '서버에서 다운로드',
isoTargetDir: 'ISO 대상 경로',
isoTargetDirHelper: '로컬 업로드 또는 서버 다운로드 ISO가 디렉터리에 저장됩니다.',
isoTargetDirOptional: 'ISO 대상 경로가 입력되지 않아 원래 ISO 소스 파일 경로를 사용합니다.',
isoTargetDirAvailable: 'ISO 대상 경로를 사용할 있습니다.',
isoTargetDirUnavailable: 'ISO 대상 경로는 사용 가능한 VM 스토리지 내에 있어야 합니다.',
isoTargetDirCheckRequired: '저장하기 전에 ISO 대상 경로를 확인하세요.',
checkPath: '확인',
addingIsoRecord: 'ISO 레코드를 추가하는 ',
isoSize: 'ISO 크기',
deleteIsoConfirm: ' 삭제 작업은 되돌릴 없습니다. 계속하시겠습니까?',
deleteSourceFile: '원본 파일 삭제',
+8 -28
View File
@@ -5750,7 +5750,6 @@ const message = {
dependencies: 'Kebergantungan',
dependencyPurpose: 'Tujuan',
dependencyPurposeMap: {
kvm: 'Menyediakan sokongan virtualisasi perkakasan untuk mempercepat pelaksanaan VM.',
libvirt: 'Menyediakan perkhidmatan pengurusan VM untuk kitar hayat dan penjadualan sumber.',
storage: 'Menyediakan direktori storan lalai atau kolam storan untuk fail cakera VM.',
},
@@ -5758,7 +5757,6 @@ const message = {
'Semakan kebergantungan VM gagal. Selesaikan kebergantungan sebelum menggunakan mesin maya.',
helperUnavailable:
'Permulaan keupayaan VM gagal. Semak log Core atau naik taraf semula sebelum menggunakan mesin maya.',
helperNotStart: 'Perkhidmatan VM tidak berjalan. Mulakan perkhidmatan sebelum menggunakan mesin maya.',
cpu: 'CPU',
memory: 'Memori',
disk: 'Cakera',
@@ -5769,22 +5767,15 @@ const message = {
storageLimitHelper: 'Ruang kosong semasa dalam kolam storan sasaran: {0}',
storageLimitExceeded: 'Kapasiti cakera melebihi had. Maksimum tersedia semasa: {0}.',
iso: 'ISO',
createSource: 'Sumber Cipta',
createFromTemplate: 'Cipta daripada templat',
blankDisk: 'Blank Disk',
template: 'Template',
templateName: 'Template Name',
convertToTemplate: 'Convert to Template',
sourceVM: 'Source VM',
templateSize: 'Template Size',
deleteTemplate: 'Delete Template',
deleteTemplateConfirm: 'Padam templat {0}. Operasi ini tidak boleh dibuat asal. Teruskan?',
diskSize: 'Saiz Cakera',
diskPath: 'Laluan Cakera',
diskPathHelper:
'Pilihan. Jika kosong, sistem akan mencipta <nama VM>.qcow2 dalam direktori kolam storan yang dipilih. Nilai tersuai mestilah laluan mutlak.',
imagePath: 'Laluan Imej',
imagePathHelper: 'Pilihan. Jika ditetapkan, gunakan laluan mutlak imej qcow2 sedia ada.',
isoPath: 'Laluan ISO',
storagePool: 'Kolam Storan',
network: 'Rangkaian',
@@ -5801,8 +5792,10 @@ const message = {
dhcpStart: 'Mula DHCP',
dhcpEnd: 'Tamat DHCP',
bootOrder: 'Susunan But',
bootOrderHelper:
'HD but daripada cakera dahulu dan kemudian mencuba ISO jika cakera tidak boleh dibut. CD-ROM but daripada ISO dahulu.',
bootDiskFirst: 'Cakera dahulu (HD CD-ROM)',
bootIsoFirst: 'ISO dahulu (CD-ROM HD)',
bootOrderConfirm:
'Tukar susunan but kepada {0}? Pada permulaan seterusnya, VM akan mencuba peranti boleh but yang sedang dipasang mengikut susunan ini.',
startAfterCreate: 'Mula selepas dicipta',
autoStart: 'Mula automatik',
resourceAutoStart: 'Mula automatik',
@@ -5810,16 +5803,6 @@ const message = {
available: 'Tersedia',
vmCount: 'VM Terpaut',
usedIPs: 'IP Digunakan',
syncFromServer: 'Segerak dari Pelayan',
notFound: 'Tidak ditemui',
resourceStatus: {
running: 'Berjalan',
inactive: 'Tidak aktif',
building: 'Membina',
degraded: 'Menurun',
inaccessible: 'Tidak boleh diakses',
unknown: 'Tidak diketahui',
},
monitor: 'Monitor',
monitorNotReady: 'The virtual machine is not running. Monitoring data is unavailable.',
monitorLoadFailed: 'Failed to get VM monitoring data.',
@@ -5846,10 +5829,11 @@ const message = {
snapshot: 'Snapshot',
createSnapshot: 'Create Snapshot',
recoverSnapshot: 'Recover Snapshot',
snapshotName: 'Snapshot Name',
snapshotSize: 'Snapshot Size',
snapshotSize: 'Penggunaan',
currentSnapshot: 'Current',
snapshotEmpty: 'No snapshots',
snapshotOperationHelper:
'Syot kilat yang sedang digunakan tidak boleh dipadam. Syot kilat hanya boleh dipulihkan apabila mesin maya dimatikan.',
snapshotRecoverConfirm:
'Recover virtual machine [{1}] to snapshot [{0}]? The VM disk will be restored to the snapshot state.',
interface: 'Antara Muka Rangkaian',
@@ -5871,11 +5855,7 @@ const message = {
isoTargetDir: 'Laluan Sasaran ISO',
isoTargetDirHelper:
'ISO yang dimuat naik secara tempatan atau dimuat turun daripada pelayan akan disimpan ke direktori ini.',
isoTargetDirOptional: 'Tiada laluan sasaran ISO ditetapkan. Laluan fail sumber ISO asal akan digunakan.',
isoTargetDirAvailable: 'Laluan sasaran ISO tersedia.',
isoTargetDirUnavailable: 'Laluan sasaran ISO mesti berada dalam storan pool VM yang tersedia.',
isoTargetDirCheckRequired: 'Semak laluan sasaran ISO sebelum menyimpan.',
checkPath: 'Semak',
addingIsoRecord: 'Menambah rekod ISO',
isoSize: 'Saiz ISO',
deleteIsoConfirm: 'Operasi pemadaman ini tidak boleh dibuat asal. Teruskan?',
deleteSourceFile: 'Padam fail sumber',
+8 -30
View File
@@ -5899,7 +5899,6 @@ const message = {
dependencies: 'Dependências',
dependencyPurpose: 'Finalidade',
dependencyPurposeMap: {
kvm: 'Fornece suporte de virtualização por hardware para execução acelerada de VMs.',
libvirt:
'Fornece serviços de gerenciamento de VMs para controle de ciclo de vida e agendamento de recursos.',
storage:
@@ -5909,7 +5908,6 @@ const message = {
'As verificações de dependência da VM falharam. Corrija as dependências antes de usar máquinas virtuais.',
helperUnavailable:
'A inicialização da capacidade de VM falhou. Verifique os logs do Core ou atualize novamente antes de usar VMs.',
helperNotStart: 'O serviço de VM não está em execução. Inicie o serviço antes de usar máquinas virtuais.',
cpu: 'CPU',
memory: 'Memória',
disk: 'Disco',
@@ -5920,22 +5918,15 @@ const message = {
storageLimitHelper: 'Espaço livre atual no pool de armazenamento de destino: {0}',
storageLimitExceeded: 'A capacidade do disco excede o limite. Máximo disponível no momento: {0}.',
iso: 'ISO',
createSource: 'Origem da criação',
createFromTemplate: 'Criar a partir de modelo',
blankDisk: 'Blank Disk',
template: 'Template',
templateName: 'Template Name',
convertToTemplate: 'Convert to Template',
sourceVM: 'Source VM',
templateSize: 'Template Size',
deleteTemplate: 'Delete Template',
deleteTemplateConfirm: 'Excluir modelo {0}. Esta operação não pode ser desfeita. Continuar?',
diskSize: 'Tamanho do Disco',
diskPath: 'Caminho do Disco',
diskPathHelper:
'Opcional. Se vazio, o sistema cria <nome da VM>.qcow2 no diretório do pool de armazenamento selecionado. Valores personalizados devem ser caminhos absolutos.',
imagePath: 'Caminho da Imagem',
imagePathHelper: 'Opcional. Se definido, use o caminho absoluto de uma imagem qcow2 existente.',
isoPath: 'Caminho do ISO',
storagePool: 'Pool de Armazenamento',
network: 'Rede',
@@ -5952,8 +5943,10 @@ const message = {
dhcpStart: 'Início DHCP',
dhcpEnd: 'Fim DHCP',
bootOrder: 'Ordem de Boot',
bootOrderHelper:
'HD inicializa pelo disco primeiro e tenta o ISO se o disco não for inicializável. CD-ROM inicializa pelo ISO primeiro.',
bootDiskFirst: 'Disco primeiro (HD CD-ROM)',
bootIsoFirst: 'ISO primeiro (CD-ROM HD)',
bootOrderConfirm:
'Alterar a ordem de boot para {0}? Na próxima inicialização, a VM tentará nesta ordem os dispositivos inicializáveis que estiverem montados.',
startAfterCreate: 'Iniciar após criação',
autoStart: 'Inicialização automática',
resourceAutoStart: 'Inicialização automática',
@@ -5961,16 +5954,6 @@ const message = {
available: 'Disponível',
vmCount: 'VMs Vinculadas',
usedIPs: 'IPs Usados',
syncFromServer: 'Sincronizar do Servidor',
notFound: 'Não encontrado',
resourceStatus: {
running: 'Em execução',
inactive: 'Inativo',
building: 'Construindo',
degraded: 'Degradado',
inaccessible: 'Inacessível',
unknown: 'Desconhecido',
},
monitor: 'Monitor',
monitorNotReady: 'The virtual machine is not running. Monitoring data is unavailable.',
monitorLoadFailed: 'Failed to get VM monitoring data.',
@@ -5997,10 +5980,11 @@ const message = {
snapshot: 'Snapshot',
createSnapshot: 'Create Snapshot',
recoverSnapshot: 'Recover Snapshot',
snapshotName: 'Snapshot Name',
snapshotSize: 'Snapshot Size',
snapshotSize: 'Uso',
currentSnapshot: 'Current',
snapshotEmpty: 'No snapshots',
snapshotOperationHelper:
'O snapshot em uso não pode ser excluído. Os snapshots podem ser restaurados quando a máquina virtual estiver desligada.',
snapshotRecoverConfirm:
'Recover virtual machine [{1}] to snapshot [{0}]? The VM disk will be restored to the snapshot state.',
interface: 'Interface de Rede',
@@ -6021,13 +6005,7 @@ const message = {
downloadFromServer: 'Baixar do servidor',
isoTargetDir: 'Caminho de destino ISO',
isoTargetDirHelper: 'ISOs enviados localmente ou baixados do servidor serão salvos neste diretório.',
isoTargetDirOptional:
'Nenhum caminho de destino ISO foi definido. O caminho original do arquivo ISO será usado.',
isoTargetDirAvailable: 'O caminho de destino ISO está disponível.',
isoTargetDirUnavailable:
'O caminho de destino ISO deve estar em um pool de armazenamento de VM disponível.',
isoTargetDirCheckRequired: 'Verifique o caminho de destino ISO antes de salvar.',
checkPath: 'Verificar',
addingIsoRecord: 'Adicionando registro ISO',
isoSize: 'Tamanho do ISO',
deleteIsoConfirm: 'Esta operação de exclusão não pode ser desfeita. Continuar?',
deleteSourceFile: 'Excluir arquivo de origem',
+8 -30
View File
@@ -5749,7 +5749,6 @@ const message = {
dependencies: 'Зависимости',
dependencyPurpose: 'Назначение',
dependencyPurposeMap: {
kvm: 'Предоставляет аппаратную виртуализацию для ускоренного запуска виртуальных машин.',
libvirt: 'Предоставляет службу управления ВМ, отвечает за жизненный цикл и распределение ресурсов.',
storage: 'Предоставляет каталог хранения по умолчанию или пул хранения для файлов дисков ВМ.',
},
@@ -5757,8 +5756,6 @@ const message = {
'Проверка зависимостей ВМ не пройдена. Исправьте зависимости перед использованием виртуальных машин.',
helperUnavailable:
'Не удалось инициализировать возможности ВМ. Проверьте журналы Core или повторите обновление перед использованием виртуальных машин.',
helperNotStart:
'Служба виртуальных машин не запущена. Запустите службу перед использованием виртуальных машин.',
cpu: 'CPU',
memory: 'Память',
disk: 'Диск',
@@ -5769,23 +5766,15 @@ const message = {
storageLimitHelper: 'Текущее свободное место в целевом пуле хранения: {0}',
storageLimitExceeded: 'Ёмкость диска превышает лимит. Текущий максимум: {0}.',
iso: 'ISO',
createSource: 'Источник создания',
createFromTemplate: 'Создать из шаблона',
blankDisk: 'Blank Disk',
template: 'Template',
templateName: 'Template Name',
convertToTemplate: 'Convert to Template',
sourceVM: 'Source VM',
templateSize: 'Template Size',
deleteTemplate: 'Delete Template',
deleteTemplateConfirm: 'Удалить шаблон {0}. Эту операцию нельзя отменить. Продолжить?',
diskSize: 'Размер диска',
diskPath: 'Путь к диску',
diskPathHelper:
'Можно оставить пустым. Система автоматически создаст ИмяВМ.qcow2 в каталоге выбранного пула хранения. Если указано, путь должен быть абсолютным.',
imagePath: 'Путь к образу',
imagePathHelper:
'Можно оставить пустым. Если указано, используйте абсолютный путь к существующему образу qcow2.',
isoPath: 'Путь к ISO',
storagePool: 'Пул хранения',
network: 'Сеть',
@@ -5802,8 +5791,10 @@ const message = {
dhcpStart: 'Начальный адрес DHCP',
dhcpEnd: 'Конечный адрес DHCP',
bootOrder: 'Порядок загрузки',
bootOrderHelper:
'HD сначала загружает с диска, а затем пробует ISO, если диск не загрузочный. CD-ROM сначала загружает с ISO.',
bootDiskFirst: 'Сначала диск (HD CD-ROM)',
bootIsoFirst: 'Сначала ISO (CD-ROM HD)',
bootOrderConfirm:
'Изменить порядок загрузки на {0}? При следующем запуске ВМ проверит в этом порядке подключённые загрузочные устройства.',
startAfterCreate: 'Запустить после создания',
autoStart: 'Автозапуск',
resourceAutoStart: 'Автозапуск',
@@ -5811,16 +5802,6 @@ const message = {
available: 'Доступно',
vmCount: 'Связанные ВМ',
usedIPs: 'Использованные IP',
syncFromServer: 'Синхронизировать с сервера',
notFound: 'Не существует',
resourceStatus: {
running: 'Работает',
inactive: 'Не запущено',
building: 'Создаётся',
degraded: 'Деградировано',
inaccessible: 'Недоступно',
unknown: 'Неизвестно',
},
monitor: 'Monitor',
monitorNotReady: 'The virtual machine is not running. Monitoring data is unavailable.',
monitorLoadFailed: 'Failed to get VM monitoring data.',
@@ -5848,10 +5829,11 @@ const message = {
snapshot: 'Snapshot',
createSnapshot: 'Create Snapshot',
recoverSnapshot: 'Recover Snapshot',
snapshotName: 'Snapshot Name',
snapshotSize: 'Snapshot Size',
snapshotSize: 'Использовано',
currentSnapshot: 'Current',
snapshotEmpty: 'No snapshots',
snapshotOperationHelper:
'Используемый снимок нельзя удалить. Восстановление снимка доступно только при выключенной виртуальной машине.',
snapshotRecoverConfirm:
'Recover virtual machine [{1}] to snapshot [{0}]? The VM disk will be restored to the snapshot state.',
interface: 'Сетевой интерфейс',
@@ -5872,11 +5854,7 @@ const message = {
downloadFromServer: 'Скачать с сервера',
isoTargetDir: 'Целевой путь ISO',
isoTargetDirHelper: 'ISO, загруженные локально или скачанные с сервера, будут сохранены в этот каталог.',
isoTargetDirOptional: 'Целевой путь ISO не указан. Будет использован исходный путь файла ISO.',
isoTargetDirAvailable: 'Целевой путь ISO доступен.',
isoTargetDirUnavailable: 'Целевой путь ISO должен находиться в доступном пуле хранения ВМ.',
isoTargetDirCheckRequired: 'Проверьте целевой путь ISO перед сохранением.',
checkPath: 'Проверить',
addingIsoRecord: 'Добавление записи ISO',
isoSize: 'Размер ISO',
deleteIsoConfirm: 'Эту операцию удаления нельзя отменить. Продолжить?',
deleteSourceFile: 'Удалить исходный файл',
+8 -28
View File
@@ -5738,7 +5738,6 @@ const message = {
dependencies: 'Bağımlılıklar',
dependencyPurpose: 'Amaç',
dependencyPurposeMap: {
kvm: 'Hızlandırılmış VM çalıştırma için donanım sanallaştırma desteği sağlar.',
libvirt: 'Yaşam döngüsü denetimi ve kaynak zamanlaması için VM yönetim hizmetleri sağlar.',
storage: 'VM disk dosyaları için varsayılan depolama dizinini veya depolama havuzunu sağlar.',
},
@@ -5746,7 +5745,6 @@ const message = {
'VM bağımlılık denetimleri başarısız oldu. Sanal makineleri kullanmadan önce bağımlılıkları düzeltin.',
helperUnavailable:
'VM yeteneği başlatılamadı. Sanal makineleri kullanmadan önce Core günlüklerini kontrol edin veya yeniden yükseltin.',
helperNotStart: 'VM hizmeti çalışmıyor. Sanal makineleri kullanmadan önce hizmeti başlatın.',
cpu: 'CPU',
memory: 'Bellek',
disk: 'Disk',
@@ -5757,22 +5755,15 @@ const message = {
storageLimitHelper: 'Hedef depolama havuzundaki mevcut boş alan: {0}',
storageLimitExceeded: 'Disk kapasitesi sınırı aşıyor. Şu anki maksimum kullanılabilir: {0}.',
iso: 'ISO',
createSource: 'Oluşturma Kaynağı',
createFromTemplate: 'Şablondan oluştur',
blankDisk: 'Blank Disk',
template: 'Template',
templateName: 'Template Name',
convertToTemplate: 'Convert to Template',
sourceVM: 'Source VM',
templateSize: 'Template Size',
deleteTemplate: 'Delete Template',
deleteTemplateConfirm: '{0} şablonu silinsin. Bu işlem geri alınamaz. Devam edilsin mi?',
diskSize: 'Disk Boyutu',
diskPath: 'Disk Yolu',
diskPathHelper:
'İsteğe bağlıdır. Boş bırakılırsa sistem seçilen depolama havuzu dizininde <VM adı>.qcow2 oluşturur. Özel değerler mutlak yol olmalıdır.',
imagePath: 'İmaj Yolu',
imagePathHelper: 'İsteğe bağlıdır. Ayarlanırsa mevcut bir qcow2 imajının mutlak yolunu kullanın.',
isoPath: 'ISO Yolu',
storagePool: 'Depolama Havuzu',
network: '',
@@ -5789,8 +5780,10 @@ const message = {
dhcpStart: 'DHCP Başlangıcı',
dhcpEnd: 'DHCP Bitişi',
bootOrder: 'Önyükleme Sırası',
bootOrderHelper:
'HD önce diskten önyükler, disk önyüklenebilir değilse ISOyu dener. CD-ROM önce ISOdan önyükler.',
bootDiskFirst: 'Önce disk (HD CD-ROM)',
bootIsoFirst: 'Önce ISO (CD-ROM HD)',
bootOrderConfirm:
'Önyükleme sırası {0} olarak değiştirilsin mi? Sanal makine bir sonraki başlangıçta bağlı ve önyüklenebilir aygıtları bu sırayla dener.',
startAfterCreate: 'Oluşturduktan sonra başlat',
autoStart: 'Otomatik başlat',
resourceAutoStart: 'Otomatik başlat',
@@ -5798,16 +5791,6 @@ const message = {
available: 'Kullanılabilir',
vmCount: 'Bağlı VMler',
usedIPs: 'Kullanılan IPler',
syncFromServer: 'Sunucudan senkronize et',
notFound: 'Bulunamadı',
resourceStatus: {
running: 'Çalışıyor',
inactive: 'Etkin değil',
building: 'Oluşturuluyor',
degraded: 'Bozulmuş',
inaccessible: 'Erişilemez',
unknown: 'Bilinmiyor',
},
monitor: 'Monitor',
monitorNotReady: 'The virtual machine is not running. Monitoring data is unavailable.',
monitorLoadFailed: 'Failed to get VM monitoring data.',
@@ -5835,10 +5818,11 @@ const message = {
snapshot: 'Snapshot',
createSnapshot: 'Create Snapshot',
recoverSnapshot: 'Recover Snapshot',
snapshotName: 'Snapshot Name',
snapshotSize: 'Snapshot Size',
snapshotSize: 'Kullanım',
currentSnapshot: 'Current',
snapshotEmpty: 'No snapshots',
snapshotOperationHelper:
'Kullanımdaki anlık görüntü silinemez. Anlık görüntüler yalnızca sanal makine kapalıyken geri yüklenebilir.',
snapshotRecoverConfirm:
'Recover virtual machine [{1}] to snapshot [{0}]? The VM disk will be restored to the snapshot state.',
interface: ' Arayüzü',
@@ -5859,11 +5843,7 @@ const message = {
downloadFromServer: 'Sunucudan İndir',
isoTargetDir: 'ISO Hedef Yolu',
isoTargetDirHelper: 'Yerel olarak yüklenen veya sunucudan indirilen ISO dosyaları bu dizine kaydedilir.',
isoTargetDirOptional: 'ISO hedef yolu ayarlanmadı. Orijinal ISO kaynak dosya yolu kullanılacak.',
isoTargetDirAvailable: 'ISO hedef yolu kullanılabilir.',
isoTargetDirUnavailable: 'ISO hedef yolu kullanılabilir bir VM depolama havuzunun içinde olmalıdır.',
isoTargetDirCheckRequired: 'Kaydetmeden önce ISO hedef yolunu kontrol edin.',
checkPath: 'Kontrol Et',
addingIsoRecord: 'ISO kaydı ekleniyor',
isoSize: 'ISO Boyutu',
deleteIsoConfirm: 'Bu silme işlemi geri alınamaz. Devam edilsin mi?',
deleteSourceFile: 'Kaynak dosyayı sil',
+6 -26
View File
@@ -5269,13 +5269,11 @@ const message = {
dependencies: '依賴',
dependencyPurpose: '作用',
dependencyPurposeMap: {
kvm: '提供硬體虛擬化能力是虛擬機加速執行的基礎',
libvirt: '提供虛擬機管理服務負責虛擬機生命週期和資源調度',
storage: '提供預設儲存目錄或儲存池用於保存虛擬機磁碟檔案',
},
dependencyNotReady: '虛擬機依賴檢測未通過請處理依賴後再使用虛擬機功能',
helperUnavailable: '虛擬機能力初始化失敗請檢查 Core 日誌或重新升級後再使用虛擬機功能',
helperNotStart: '虛擬機執行環境未就緒請處理主機虛擬化服務後再使用虛擬機功能',
cpu: 'CPU',
memory: '記憶體',
disk: '磁碟',
@@ -5286,21 +5284,15 @@ const message = {
storageLimitHelper: '目標儲存池目前可用空間{0}',
storageLimitExceeded: '磁碟容量超出限制目前最大可用{0}',
iso: '鏡像',
createSource: '建立來源',
createFromTemplate: '從範本啟動',
blankDisk: '空白磁碟',
template: '範本',
templateName: '範本名稱',
convertToTemplate: '轉為範本',
sourceVM: '來源虛擬機',
templateSize: '範本大小',
deleteTemplate: '刪除範本',
deleteTemplateConfirm: '刪除範本 {0}該操作不可回滾是否繼續',
diskSize: '磁碟容量',
diskPath: '磁碟路徑',
diskPathHelper: '可留空系統將在所選儲存池目錄下自動建立 虛擬機名稱.qcow2如填寫必須是絕對路徑',
imagePath: '映像路徑',
imagePathHelper: '可留空如填寫需為已存在的 qcow2 映像絕對路徑',
isoPath: '鏡像路徑',
storagePool: '儲存池',
network: '網路',
@@ -5316,7 +5308,9 @@ const message = {
dhcpStart: 'DHCP 起始位址',
dhcpEnd: 'DHCP 結束位址',
bootOrder: '啟動項',
bootOrderHelper: 'HD 表示優先從磁碟啟動磁碟不可啟動時再嘗試鏡像CD-ROM 表示優先從鏡像啟動',
bootDiskFirst: '磁碟優先HD CD-ROM',
bootIsoFirst: '鏡像優先CD-ROM HD',
bootOrderConfirm: '確定將啟動順序修改為 {0} 虛擬機下次啟動時將按此順序嘗試目前已掛載且可啟動的裝置',
startAfterCreate: '建立後啟動',
autoStart: '開機自啟',
resourceAutoStart: '開機自啟',
@@ -5324,16 +5318,6 @@ const message = {
available: '可用',
vmCount: '關聯虛擬機',
usedIPs: '已用 IP',
syncFromServer: '從伺服器同步',
notFound: '不存在',
resourceStatus: {
running: '執行中',
inactive: '未啟動',
building: '建置中',
degraded: '降級',
inaccessible: '無法存取',
unknown: '未知',
},
monitor: '監控',
monitorNotReady: '虛擬機未執行無法取得監控資料',
monitorLoadFailed: '取得虛擬機監控資料失敗',
@@ -5360,10 +5344,10 @@ const message = {
snapshot: '快照',
createSnapshot: '建立快照',
recoverSnapshot: '恢復快照',
snapshotName: '快照名稱',
snapshotSize: '快照大小',
snapshotSize: '佔用',
currentSnapshot: '目前',
snapshotEmpty: '暫無快照',
snapshotOperationHelper: '目前使用中的快照不允許刪除僅當虛擬機處於關機狀態時才允許恢復快照',
snapshotRecoverConfirm: '確認將虛擬機 [{1}] 恢復到快照 [{0}]恢復後虛擬機磁碟會回到該快照狀態',
interface: '網路介面',
device: '裝置',
@@ -5382,11 +5366,7 @@ const message = {
downloadFromServer: '從伺服器下載',
isoTargetDir: '鏡像目標路徑',
isoTargetDirHelper: '本機上傳或從伺服器下載的鏡像會儲存到該目錄',
isoTargetDirOptional: '未填寫鏡像目標路徑將直接使用鏡像來源檔案路徑',
isoTargetDirAvailable: '鏡像目標路徑可用',
isoTargetDirUnavailable: '鏡像目標路徑必須位於可用的虛擬機儲存池內',
isoTargetDirCheckRequired: '請先檢查鏡像目標路徑檢查通過後再儲存',
checkPath: '檢查',
addingIsoRecord: '正在新增 ISO 記錄',
isoSize: '鏡像大小',
deleteIsoConfirm: '刪除操作不可回滾是否繼續',
deleteSourceFile: '刪除源檔案',
+6 -31
View File
@@ -5262,13 +5262,11 @@ const message = {
dependencies: '依赖',
dependencyPurpose: '作用',
dependencyPurposeMap: {
kvm: '提供硬件虚拟化能力是虚拟机加速运行的基础',
libvirt: '提供虚拟机管理服务负责虚拟机生命周期和资源调度',
storage: '提供默认存储目录或存储池用于保存虚拟机磁盘文件',
},
dependencyNotReady: '虚拟机依赖检测未通过请处理后再使用虚拟机功能',
helperUnavailable: '虚拟机能力初始化失败请检查 Core 日志或重新升级后再使用虚拟机功能',
helperNotStart: '虚拟机运行环境未就绪请处理宿主机虚拟化服务后再使用虚拟机功能',
kvmUnavailable: '未检测到可用的 KVM 硬件虚拟化能力',
kvmCheckCpu: '确认宿主机 CPU 支持 Intel VT-x AMD-V 虚拟化能力',
kvmCheckBios: '进入 BIOS/UEFI 开启虚拟化相关选项',
@@ -5277,7 +5275,6 @@ const message = {
cpu: 'CPU',
memory: '内存',
disk: '磁盘',
totalVM: '虚拟机总数',
abnormal: '异常',
resourceOverview: '资源概况',
cpuAllocated: 'CPU 分配',
@@ -5285,14 +5282,10 @@ const message = {
storageUsed: '存储使用',
riskReminder: '风险提醒',
noRisk: '暂无风险',
quickEntry: '快捷入口',
runtimeHealth: '运行环境',
runtimeReady: '虚拟机运行环境正常',
runtimeAbnormal: '虚拟机运行环境异常',
environmentCheck: '环境检测',
noDependency: '暂无依赖检测数据',
storageOverview: '存储池概况',
recentVM: '最近虚拟机',
totalAllocated: '按虚拟机配置总量统计',
runningAllocated: '运行中占用{0}',
storageAvailable: '剩余可用{0}',
@@ -5311,21 +5304,15 @@ const message = {
storageLimitHelper: '目标存储池当前可用空间{0}',
storageLimitExceeded: '磁盘容量超出限制当前最大可用{0}',
iso: '镜像',
createSource: '创建来源',
createFromTemplate: '从模板启动',
blankDisk: '空白磁盘',
template: '模板',
templateName: '模板名称',
convertToTemplate: '转为模板',
sourceVM: '来源虚拟机',
templateSize: '模板大小',
deleteTemplate: '删除模板',
deleteTemplateConfirm: '删除模板 {0}该操作不可回滚是否继续',
diskSize: '磁盘容量',
diskPath: '磁盘路径',
diskPathHelper: '可留空系统将在所选存储池目录下自动创建 虚拟机名称.qcow2如填写必须是绝对路径',
imagePath: '镜像路径',
imagePathHelper: '可留空如填写需为已存在的 qcow2 镜像绝对路径',
isoPath: '镜像源文件',
storagePool: '存储池',
network: '网络',
@@ -5341,7 +5328,9 @@ const message = {
dhcpStart: 'DHCP 起始地址',
dhcpEnd: 'DHCP 结束地址',
bootOrder: '启动项',
bootOrderHelper: 'HD 表示优先从磁盘启动磁盘不可启动时再尝试镜像CD-ROM 表示优先从镜像启动',
bootDiskFirst: '磁盘优先HD CD-ROM',
bootIsoFirst: '镜像优先CD-ROM HD',
bootOrderConfirm: '确定将启动顺序修改为 {0} 虚拟机下次启动时将按此顺序尝试当前已挂载且可启动的设备',
startAfterCreate: '创建后启动',
autoStart: '开机自启',
resourceAutoStart: '开机自启',
@@ -5349,16 +5338,6 @@ const message = {
available: '可用',
vmCount: '关联虚拟机',
usedIPs: '已用 IP',
syncFromServer: '从服务器同步',
notFound: '不存在',
resourceStatus: {
running: '运行中',
inactive: '未启动',
building: '构建中',
degraded: '降级',
inaccessible: '不可访问',
unknown: '未知',
},
monitor: '监控',
monitorNotReady: '虚拟机未运行无法获取监控数据',
monitorLoadFailed: '获取虚拟机监控数据失败',
@@ -5385,10 +5364,10 @@ const message = {
snapshot: '快照',
createSnapshot: '创建快照',
recoverSnapshot: '恢复快照',
snapshotName: '快照名称',
snapshotSize: '快照大小',
snapshotSize: '占用',
currentSnapshot: '当前',
snapshotEmpty: '暂无快照',
snapshotOperationHelper: '当前正在使用的快照不允许删除仅当虚拟机处于已关机状态时才允许恢复快照',
snapshotRecoverConfirm: '确认将虚拟机 [{1}] 恢复到快照 [{0}]恢复后虚拟机磁盘会回到该快照状态',
interface: '网络接口',
device: '设备',
@@ -5407,11 +5386,7 @@ const message = {
downloadFromServer: '从服务器下载',
isoTargetDir: '镜像目标路径',
isoTargetDirHelper: '本地上传或从服务器下载的镜像会保存到该目录',
isoTargetDirOptional: '未填写镜像目标路径将直接使用镜像源文件路径',
isoTargetDirAvailable: '镜像目标路径可用',
isoTargetDirUnavailable: '镜像目标路径必须位于可用的虚拟机存储池内',
isoTargetDirCheckRequired: '请先检查镜像目标路径检查通过后再保存',
checkPath: '检查',
addingIsoRecord: '正在添加 ISO 记录',
isoSize: '镜像大小',
deleteIsoConfirm: '删除操作不可回滚是否继续',
deleteSourceFile: '删除源文件',
+31 -43
View File
@@ -26,7 +26,7 @@ const clearLoginStatus = () => {
clearLicenseStatus();
};
router.beforeEach(async (to, from, next) => {
router.beforeEach(async (to, from) => {
const { entrance, isEnterprise, isEnterpriseLicenseLoaded, isEnterpriseLicensed, isLogin } = useGlobalStore();
NProgress.start();
axiosCanceler.removeAllPending();
@@ -35,85 +35,75 @@ router.beforeEach(async (to, from, next) => {
clearLoginStatus();
}
if (!isLogin.value && !noLoginWhiteList.includes(String(to.name))) {
next(
entrance.value
? {
name: 'entrance',
params: { code: entrance.value },
}
: {
name: 'login',
},
);
NProgress.done();
return;
return entrance.value
? {
name: 'entrance',
params: { code: entrance.value },
}
: {
name: 'login',
};
}
if (to.name === 'login' && !isLogin.value && entrance.value) {
next({
NProgress.done();
return {
name: 'entrance',
params: { code: entrance.value },
});
NProgress.done();
return;
};
}
if (to.name === 'login' && isLogin.value) {
next({
name: 'home',
});
NProgress.done();
return;
return {
name: 'home',
};
}
if (to.name === 'entrance' && isLogin.value) {
if (to.params.code === entrance.value) {
next({
name: 'home',
});
NProgress.done();
return;
return {
name: 'home',
};
}
next({ name: '404' });
NProgress.done();
return;
return { name: '404' };
}
if (isLogin.value && isEnterprise.value && !enterpriseLicenseCheckWhiteList.includes(String(to.name))) {
if (!isEnterpriseLicenseLoaded.value) {
await loadProductProFromDB();
}
if (!isEnterpriseLicensed.value) {
next({ name: 'EnterpriseLicenseRequired', query: { code: String(to.params.code || '') } });
NProgress.done();
return;
return { name: 'EnterpriseLicenseRequired', query: { code: String(to.params.code || '') } };
}
}
if (to.name === 'EnterpriseLicenseRequired') {
if (!isLogin.value) {
next({
NProgress.done();
return {
name: 'entrance',
params: to.params,
});
NProgress.done();
return;
};
}
if (!isEnterprise.value || isEnterpriseLicensed.value) {
next({ name: 'home' });
NProgress.done();
return;
return { name: 'home' };
}
return next();
return true;
}
if (to.path === '/apps/all' && to.query.install != undefined) {
return next();
return true;
}
if (to.name === 'Expired') {
return next();
return true;
}
const activeMenuKey = 'cachedRoute' + (to.meta.activeMenu || '');
if (to.query.uncached != undefined) {
const query = { ...to.query };
delete query.uncached;
localStorage.removeItem(activeMenuKey);
return next({ path: to.path, query });
return { path: to.path, query };
}
const cachedRoute = localStorage.getItem(activeMenuKey);
@@ -127,20 +117,18 @@ router.beforeEach(async (to, from, next) => {
const cachedRouteInfo = router.resolve(cachedRoute);
if (cachedRouteInfo.matched.length > 0 && hasRouteAccess(cachedRouteInfo)) {
isRedirecting = true;
next(cachedRoute);
NProgress.done();
return;
return cachedRoute;
}
localStorage.removeItem(activeMenuKey);
}
if (!hasRouteAccess(to)) {
MsgError(i18n.global.t('commons.res.forbidden'));
next(false);
NProgress.done();
return;
return false;
}
return next();
return true;
});
router.afterEach((to) => {