mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-16 14:57:05 +08:00
feat: support app and image synchronization (#13067)
This commit is contained in:
@@ -413,10 +413,15 @@ func (b *BaseApi) Backup(c *gin.Context) {
|
||||
|
||||
switch req.Type {
|
||||
case "app":
|
||||
if _, err := backupService.AppBackup(req); err != nil {
|
||||
record, err := backupService.AppBackup(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
if req.IsImmediate {
|
||||
helper.SuccessWithData(c, record)
|
||||
return
|
||||
}
|
||||
case "mysql", "mariadb", constant.AppMysqlCluster:
|
||||
if err := backupService.MysqlBackup(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
|
||||
@@ -65,14 +65,15 @@ type UploadForRecover struct {
|
||||
}
|
||||
|
||||
type CommonBackup struct {
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql mongodb mysql-cluster postgresql-cluster redis-cluster container compose"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
Secret string `json:"secret"`
|
||||
StopBefore bool `json:"stopBefore"`
|
||||
TaskID string `json:"taskID"`
|
||||
FileName string `json:"fileName"`
|
||||
Args []string `json:"args"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql mongodb mysql-cluster postgresql-cluster redis-cluster container compose"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
Secret string `json:"secret"`
|
||||
IsImmediate bool `json:"isImmediate"`
|
||||
StopBefore bool `json:"stopBefore"`
|
||||
TaskID string `json:"taskID"`
|
||||
FileName string `json:"fileName"`
|
||||
Args []string `json:"args"`
|
||||
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ type AppInstallDTO struct {
|
||||
Container string `json:"container"`
|
||||
IsEdit bool `json:"isEdit"`
|
||||
LinkDB bool `json:"linkDB"`
|
||||
ResourceKeys []string `json:"resourceKeys"`
|
||||
ServiceName string `json:"serviceName"`
|
||||
}
|
||||
|
||||
|
||||
@@ -1620,6 +1620,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated, sync, checkUpda
|
||||
synAppInstall(containersMap, &installed, false)
|
||||
}
|
||||
|
||||
resourceKeys := getAppInstallResourceKeys(installed.ID)
|
||||
installDTO := response.AppInstallDTO{
|
||||
ID: installed.ID,
|
||||
Name: installed.Name,
|
||||
@@ -1641,14 +1642,15 @@ func handleInstalled(appInstallList []model.AppInstall, updated, sync, checkUpda
|
||||
Website: installed.App.Website,
|
||||
Document: installed.App.Document,
|
||||
},
|
||||
Favorite: installed.Favorite,
|
||||
SortOrder: installed.SortOrder,
|
||||
Container: installed.ContainerName,
|
||||
ServiceName: strings.ToLower(installed.ServiceName),
|
||||
Favorite: installed.Favorite,
|
||||
SortOrder: installed.SortOrder,
|
||||
Container: installed.ContainerName,
|
||||
ServiceName: strings.ToLower(installed.ServiceName),
|
||||
ResourceKeys: resourceKeys,
|
||||
}
|
||||
|
||||
if !updated && !checkUpdate {
|
||||
installDTO.LinkDB = hasLinkDB(installed.ID)
|
||||
installDTO.LinkDB = hasLinkDBFromKeys(resourceKeys)
|
||||
res = append(res, installDTO)
|
||||
continue
|
||||
}
|
||||
@@ -1656,7 +1658,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated, sync, checkUpda
|
||||
if installed.Version == "latest" {
|
||||
if checkUpdate {
|
||||
installDTO.CanUpdate = false
|
||||
installDTO.LinkDB = hasLinkDB(installed.ID)
|
||||
installDTO.LinkDB = hasLinkDBFromKeys(resourceKeys)
|
||||
res = append(res, installDTO)
|
||||
}
|
||||
continue
|
||||
@@ -1685,7 +1687,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated, sync, checkUpda
|
||||
if len(versions) == 0 {
|
||||
if checkUpdate {
|
||||
installDTO.CanUpdate = false
|
||||
installDTO.LinkDB = hasLinkDB(installed.ID)
|
||||
installDTO.LinkDB = hasLinkDBFromKeys(resourceKeys)
|
||||
res = append(res, installDTO)
|
||||
}
|
||||
continue
|
||||
@@ -1717,7 +1719,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated, sync, checkUpda
|
||||
res = append(res, installDTO)
|
||||
}
|
||||
} else if checkUpdate {
|
||||
installDTO.LinkDB = hasLinkDB(installed.ID)
|
||||
installDTO.LinkDB = hasLinkDBFromKeys(resourceKeys)
|
||||
res = append(res, installDTO)
|
||||
}
|
||||
}
|
||||
@@ -2284,13 +2286,25 @@ func needsUpdate(localTag *model.Tag, remoteTag dto.Tag, translations string) bo
|
||||
}
|
||||
|
||||
func hasLinkDB(installID uint) bool {
|
||||
return hasLinkDBFromKeys(getAppInstallResourceKeys(installID))
|
||||
}
|
||||
|
||||
func getAppInstallResourceKeys(installID uint) []string {
|
||||
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(installID))
|
||||
keys := make([]string, 0, len(resources))
|
||||
for _, resource := range resources {
|
||||
keys = append(keys, resource.Key)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func hasLinkDBFromKeys(resourceKeys []string) bool {
|
||||
hasDB := false
|
||||
if len(resources) > 0 {
|
||||
for _, resource := range resources {
|
||||
if resource.Key == constant.AppPostgres || resource.Key == constant.AppMysql ||
|
||||
resource.Key == constant.AppMariaDB || resource.Key == constant.AppMysqlCluster ||
|
||||
resource.Key == constant.AppPostgresql || resource.Key == constant.AppPostgresqlCluster {
|
||||
if len(resourceKeys) > 0 {
|
||||
for _, resourceKey := range resourceKeys {
|
||||
if resourceKey == constant.AppPostgres || resourceKey == constant.AppMysql ||
|
||||
resourceKey == constant.AppMariaDB || resourceKey == constant.AppMysqlCluster ||
|
||||
resourceKey == constant.AppPostgresql || resourceKey == constant.AppPostgresqlCluster {
|
||||
hasDB = true
|
||||
break
|
||||
}
|
||||
|
||||
@@ -63,11 +63,30 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, er
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = handleAppBackup(&install, nil, record.ID, backupDir, fileName, "", req.Secret, req.TaskID); err != nil {
|
||||
global.LOG.Errorf("backup app %s failed, err: %v", req.DetailName, err)
|
||||
return nil, err
|
||||
if !req.IsImmediate {
|
||||
if err = handleAppBackup(&install, nil, record.ID, backupDir, fileName, "", req.Secret, req.TaskID); err != nil {
|
||||
backupRepo.UpdateRecordByMap(record.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
global.LOG.Errorf("backup app %s failed, err: %v", req.DetailName, err)
|
||||
return nil, err
|
||||
}
|
||||
return record, nil
|
||||
}
|
||||
|
||||
backupTask, err := task.NewTaskWithOps(install.Name, task.TaskBackup, task.TaskScopeBackup, req.TaskID, install.ID)
|
||||
if err != nil {
|
||||
backupRepo.UpdateRecordByMap(record.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
record.Status = constant.StatusFailed
|
||||
record.Message = err.Error()
|
||||
return nil, err
|
||||
}
|
||||
if err = doAppBackup(&install, backupTask, backupDir, fileName, "", req.Secret); err != nil {
|
||||
backupRepo.UpdateRecordByMap(record.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
record.Status = constant.StatusFailed
|
||||
record.Message = err.Error()
|
||||
return nil, err
|
||||
}
|
||||
backupRepo.UpdateRecordByMap(record.ID, map[string]interface{}{"status": constant.StatusSuccess})
|
||||
record.Status = constant.StatusSuccess
|
||||
return record, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2372,15 +2372,6 @@
|
||||
"formatZH": "检查应用安装 [name]",
|
||||
"formatEN": "check app install [name]"
|
||||
},
|
||||
"/custom/app/push": {
|
||||
"bodyKeys": [
|
||||
"appBackupID"
|
||||
],
|
||||
"paramKeys": [],
|
||||
"beforeFunctions": [],
|
||||
"formatZH": "推送应用备份 [appBackupID] 到节点",
|
||||
"formatEN": "push app backup [appBackupID] to node"
|
||||
},
|
||||
"/custom/app/sync": {
|
||||
"bodyKeys": [],
|
||||
"paramKeys": [],
|
||||
@@ -5092,4 +5083,4 @@
|
||||
"formatZH": "从主节点同步设置",
|
||||
"formatEN": "sync settings from master"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ ErrContainerMsg: 'Container {{ .name }} is abnormal; check logs'
|
||||
ErrAppBackup: 'App backup failed: {{ .name }} {{ .err }}'
|
||||
ErrVersionTooLow: '1Panel version too low to update App Store'
|
||||
ErrAppNameExist: 'The application name already exists'
|
||||
ErrAppInstallNameExist: 'App install name {{ .name }} already exists'
|
||||
AppStoreIsSyncing: 'App Store is syncing; try again later'
|
||||
ErrGetCompose: 'Failed to read docker-compose.yml: {{ .detail }}'
|
||||
ErrAppWarn: 'App status abnormal; check logs'
|
||||
|
||||
@@ -107,6 +107,7 @@ ErrContainerMsg: 'El contenedor {{ .name }} presenta anomalías. Revise el log e
|
||||
ErrAppBackup: 'Falló el respaldo de la aplicación {{ .name }} {{ .err }}'
|
||||
ErrVersionTooLow: 'La versión actual de 1Panel es demasiado baja para actualizar la tienda de aplicaciones. Actualice primero.'
|
||||
ErrAppNameExist: 'El nombre de la aplicación ya existe'
|
||||
ErrAppInstallNameExist: 'El nombre de instalación de la aplicación {{ .name }} ya existe'
|
||||
AppStoreIsSyncing: 'La tienda de aplicaciones está sincronizando, inténtelo más tarde'
|
||||
ErrGetCompose: 'Fallo al obtener el archivo docker-compose.yml {{ .detail }}'
|
||||
ErrAppWarn: 'Estado anómalo, revise el log'
|
||||
|
||||
@@ -107,6 +107,7 @@ ErrContainerMsg: '{{ .name }} コンテナが異常です。詳細について
|
||||
ErrAppBackup: '{{ .name }} アプリケーションのバックアップに失敗しました。エラー {{ .err }}'
|
||||
ErrVersionTooLow: '現在の 1Panel のバージョンが低すぎるため、App Store を更新できません。操作する前にバージョンをアップグレードしてください。'
|
||||
ErrAppNameExist: 'アプリケーション名がすでに存在します'
|
||||
ErrAppInstallNameExist: 'アプリケーションインストール名 {{ .name }} はすでに存在します'
|
||||
AppStoreIsSyncing: 'App Store が同期中です。しばらくしてからもう一度お試しください'
|
||||
ErrGetCompose: 'docker-compose.yml ファイルの取得に失敗しました {{ .detail }}'
|
||||
ErrAppWarn: '異常な状態です。ログを確認してください'
|
||||
|
||||
@@ -107,6 +107,7 @@ ErrContainerMsg: '{{ .name }} 컨테이너가 비정상입니다. 자세한 내
|
||||
ErrAppBackup: '{{ .name }} 애플리케이션 백업에 실패했습니다 {{ .err }}'
|
||||
ErrVersionTooLow: '현재 1Panel 버전이 너무 낮아 App Store를 업데이트할 수 없습니다. 작동하시기 전에 버전을 업그레이드하세요.'
|
||||
ErrAppNameExist: '응용 프로그램 이름이 이미 존재합니다'
|
||||
ErrAppInstallNameExist: '앱 설치 이름 {{ .name }} 이(가) 이미 존재합니다'
|
||||
AppStoreIsSyncing: 'App Store가 동기화 중입니다. 나중에 다시 시도하세요.'
|
||||
ErrGetCompose: 'docker-compose.yml 파일을 가져오지 못했습니다 {{ .detail }}'
|
||||
ErrAppWarn: '비정상적인 상태입니다. 로그를 확인해 주세요.'
|
||||
|
||||
@@ -107,6 +107,7 @@ ErrContainerMsg: 'Bekas ''{{ .name }} adalah tidak normal. Sila semak log pada h
|
||||
ErrAppBackup: '{{ .name }} sandaran aplikasi gagal {{ .err }}'
|
||||
ErrVersionTooLow: 'Versi 1Panel semasa terlalu rendah untuk mengemas kini App Store. Sila tingkatkan versi sebelum beroperasi.'
|
||||
ErrAppNameExist: 'Nama aplikasi sudah wujud'
|
||||
ErrAppInstallNameExist: 'Nama pemasangan aplikasi {{ .name }} sudah wujud'
|
||||
AppStoreIsSyncing: 'App Store sedang menyegerak, sila cuba sebentar lagi'
|
||||
ErrGetCompose: 'Gagal mendapatkan fail docker-compose.yml {{ .detail }}'
|
||||
ErrAppWarn: 'Status tidak normal, sila semak log'
|
||||
|
||||
@@ -107,6 +107,7 @@ ErrContainerMsg: 'O contêiner {{ .name }} está anormal., verifique o log na p
|
||||
ErrAppBackup: '{{ .name }} falha no backup do aplicativo {{ .err }}'
|
||||
ErrVersionTooLow: 'A versão atual do 1Panel é muito antiga para atualizar a App Store., atualize a versão antes de operar.'
|
||||
ErrAppNameExist: 'O nome do aplicativo já existe'
|
||||
ErrAppInstallNameExist: 'O nome de instalação do aplicativo {{ .name }} já existe'
|
||||
AppStoreIsSyncing: 'A App Store está sincronizando mais tarde'
|
||||
ErrGetCompose: 'Falha ao obter o arquivo docker-compose.yml {{ .detail }}'
|
||||
ErrAppWarn: 'Status anormal, verifique o log'
|
||||
|
||||
@@ -107,6 +107,7 @@ ErrContainerMsg: 'Контейнер {{ .name }} ненормален. Подр
|
||||
ErrAppBackup: '{{ .name }} резервное копирование приложения не удалось {{ .err }}'
|
||||
ErrVersionTooLow: 'Текущая версия 1Panel слишком низкая для обновления App Store. Пожалуйста, обновите версию перед началом работы.'
|
||||
ErrAppNameExist: 'Имя приложения уже существует'
|
||||
ErrAppInstallNameExist: 'Имя установки приложения {{ .name }} уже существует'
|
||||
AppStoreIsSyncing: 'App Store синхронизируется, повторите попытку позже'
|
||||
ErrGetCompose: 'Не удалось получить файл docker-compose.yml {{ .detail }}'
|
||||
ErrAppWarn: 'Ненормальное состояние, проверьте журнал'
|
||||
|
||||
@@ -107,6 +107,7 @@ ErrContainerMsg: '{{ .name }} konteyneri anormal. Lütfen ayrıntılar için kon
|
||||
ErrAppBackup: '{{ .name }} uygulama yedeklemesi başarısız {{ .err }}'
|
||||
ErrVersionTooLow: 'Mevcut 1Panel sürümü Uygulama Mağazasını güncellemek için çok düşük. Lütfen işlemden önce sürümü yükseltin.'
|
||||
ErrAppNameExist: 'Uygulama adı zaten mevcut'
|
||||
ErrAppInstallNameExist: '{{ .name }} uygulama kurulum adı zaten mevcut'
|
||||
AppStoreIsSyncing: 'Uygulama Mağazası senkronize ediliyor, lütfen daha sonra tekrar deneyin'
|
||||
ErrGetCompose: 'docker-compose.yml dosyası alınamadı {{ .detail }}'
|
||||
ErrAppWarn: 'Anormal durum, lütfen günlüğü kontrol edin'
|
||||
|
||||
@@ -107,6 +107,7 @@ ErrContainerMsg: '{{ .name }} 容器異常,請在容器頁面上檢視日誌'
|
||||
ErrAppBackup: '{{ .name }} 應用備份失敗 {{ .err }}'
|
||||
ErrVersionTooLow: '目前 1Panel 版本過低,無法更新應用程式商店,請升級版本之後操作'
|
||||
ErrAppNameExist: '應用程式名稱已存在'
|
||||
ErrAppInstallNameExist: '應用程式安裝名稱 {{ .name }} 已存在'
|
||||
AppStoreIsSyncing: '應用程式商店正在同步中,請稍後重試'
|
||||
ErrGetCompose: 'docker-compose.yml 檔案取得失敗!{{ .detail }}'
|
||||
ErrAppWarn: '狀態異常,請檢視日誌'
|
||||
|
||||
@@ -108,6 +108,7 @@ ErrContainerMsg: '{{ .name }} 容器异常,具体请在容器页面查看日
|
||||
ErrAppBackup: '{{ .name }} 应用备份失败 {{ .err }}'
|
||||
ErrVersionTooLow: '当前 1Panel 版本过低,无法更新应用商店,请升级版本之后操作'
|
||||
ErrAppNameExist: '应用名称已存在'
|
||||
ErrAppInstallNameExist: '应用安装名称 {{ .name }} 已存在'
|
||||
AppStoreIsSyncing: '应用商店同步中,请稍后重试'
|
||||
ErrGetCompose: "docker-compose.yml 文件获取失败!{{ .detail }}"
|
||||
ErrAppWarn: "状态异常,请查看日志"
|
||||
|
||||
@@ -2372,15 +2372,6 @@
|
||||
"formatZH": "检查应用安装 [name]",
|
||||
"formatEN": "check app install [name]"
|
||||
},
|
||||
"/custom/app/push": {
|
||||
"bodyKeys": [
|
||||
"appBackupID"
|
||||
],
|
||||
"paramKeys": [],
|
||||
"beforeFunctions": [],
|
||||
"formatZH": "推送应用备份 [appBackupID] 到节点",
|
||||
"formatEN": "push app backup [appBackupID] to node"
|
||||
},
|
||||
"/custom/app/sync": {
|
||||
"bodyKeys": [],
|
||||
"paramKeys": [],
|
||||
@@ -5092,4 +5083,4 @@
|
||||
"formatZH": "从主节点同步设置",
|
||||
"formatEN": "sync settings from master"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,10 @@ var WebUrlMap = map[string]struct{}{
|
||||
"/xpack/node/dashboard": {},
|
||||
"/xpack/node": {},
|
||||
"/xpack/simple-node": {},
|
||||
"/xpack/exchange/file": {},
|
||||
"/xpack/sync": {},
|
||||
"/xpack/sync/image": {},
|
||||
"/xpack/sync/cert": {},
|
||||
"/xpack/sync/app": {},
|
||||
"/xpack/app": {},
|
||||
"/xpack/app-upgrade": {},
|
||||
|
||||
|
||||
@@ -314,6 +314,25 @@ DBConnErr: "Error: Failed to initialize database connection, {{ .err }}"
|
||||
SystemVersion: "version: "
|
||||
SystemMode: "mode: "
|
||||
|
||||
#exchange
|
||||
LocalNodeIpFailed: "Failed to get master node IP. Edit the master node and add IP address and SSH authentication information."
|
||||
HandlePrivateKey: "Handle node private key"
|
||||
HandlePublicKey: "Handle node public key"
|
||||
ExchangeFile: "Start syncing {{ .sourcePath }} from node {{ .source }} to node {{ .dest }}:{{ .destPath }}"
|
||||
TaskRsync: "Sync"
|
||||
NodeFile: "Node file"
|
||||
ImageSyncTaskName: "Image sync {{ .source }} -> {{ .count }} nodes"
|
||||
ImageSyncSave: "Save image {{ .image }}"
|
||||
ImageSyncSaveTags: "Save image tags {{ .tags }}"
|
||||
ImageSyncToNode: "Sync image {{ .image }} to node {{ .node }}"
|
||||
ImageSyncLoad: "Load image {{ .image }} on node {{ .node }}"
|
||||
ImageSyncClean: "Clean temporary files for image {{ .image }}"
|
||||
ImageSyncNoTag: "Image {{ .image }} has no tag and will be saved by image ID"
|
||||
ImageSyncFrontendTagsIgnored: "No tags were found for image {{ .image }} on the source node. Frontend tags were ignored."
|
||||
ImageSyncHandlePrivateKey: "Handle image sync node private key"
|
||||
ImageSyncHandlePublicKey: "Handle image sync node public key"
|
||||
ImageSyncTransfer: "Start transferring image temporary file: {{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
|
||||
|
||||
#mobile app
|
||||
ErrVerifyToken: 'Token verification failed. Reset and scan again.'
|
||||
ErrInvalidToken: 'Invalid token. Reset and scan again.'
|
||||
|
||||
@@ -308,6 +308,25 @@ DBConnErr: "Error: Fallo al inicializar la conexión a la base de datos, {{ .err
|
||||
SystemVersion: "versión: "
|
||||
SystemMode: "modo: "
|
||||
|
||||
#exchange
|
||||
LocalNodeIpFailed: "Failed to get master node IP. Edit the master node and add IP address and SSH authentication information."
|
||||
HandlePrivateKey: "Handle node private key"
|
||||
HandlePublicKey: "Handle node public key"
|
||||
ExchangeFile: "Start syncing {{ .sourcePath }} from node {{ .source }} to node {{ .dest }}:{{ .destPath }}"
|
||||
TaskRsync: "Sync"
|
||||
NodeFile: "Node file"
|
||||
ImageSyncTaskName: "Image sync {{ .source }} -> {{ .count }} nodes"
|
||||
ImageSyncSave: "Save image {{ .image }}"
|
||||
ImageSyncSaveTags: "Save image tags {{ .tags }}"
|
||||
ImageSyncToNode: "Sync image {{ .image }} to node {{ .node }}"
|
||||
ImageSyncLoad: "Load image {{ .image }} on node {{ .node }}"
|
||||
ImageSyncClean: "Clean temporary files for image {{ .image }}"
|
||||
ImageSyncNoTag: "Image {{ .image }} has no tag and will be saved by image ID"
|
||||
ImageSyncFrontendTagsIgnored: "No tags were found for image {{ .image }} on the source node. Frontend tags were ignored."
|
||||
ImageSyncHandlePrivateKey: "Handle image sync node private key"
|
||||
ImageSyncHandlePublicKey: "Handle image sync node public key"
|
||||
ImageSyncTransfer: "Start transferring image temporary file: {{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
|
||||
|
||||
#mobile app
|
||||
ErrVerifyToken: 'Error al verificar el token, por favor restablezca y escanee de nuevo.'
|
||||
ErrInvalidToken: 'Token inválido, por favor restablezca y escanee de nuevo.'
|
||||
|
||||
@@ -308,6 +308,25 @@ DBConnErr: "エラー: データベース接続の初期化に失敗しました
|
||||
SystemVersion: "バージョン: "
|
||||
SystemMode: "モード: "
|
||||
|
||||
#exchange
|
||||
LocalNodeIpFailed: "Failed to get master node IP. Edit the master node and add IP address and SSH authentication information."
|
||||
HandlePrivateKey: "Handle node private key"
|
||||
HandlePublicKey: "Handle node public key"
|
||||
ExchangeFile: "Start syncing {{ .sourcePath }} from node {{ .source }} to node {{ .dest }}:{{ .destPath }}"
|
||||
TaskRsync: "Sync"
|
||||
NodeFile: "Node file"
|
||||
ImageSyncTaskName: "Image sync {{ .source }} -> {{ .count }} nodes"
|
||||
ImageSyncSave: "Save image {{ .image }}"
|
||||
ImageSyncSaveTags: "Save image tags {{ .tags }}"
|
||||
ImageSyncToNode: "Sync image {{ .image }} to node {{ .node }}"
|
||||
ImageSyncLoad: "Load image {{ .image }} on node {{ .node }}"
|
||||
ImageSyncClean: "Clean temporary files for image {{ .image }}"
|
||||
ImageSyncNoTag: "Image {{ .image }} has no tag and will be saved by image ID"
|
||||
ImageSyncFrontendTagsIgnored: "No tags were found for image {{ .image }} on the source node. Frontend tags were ignored."
|
||||
ImageSyncHandlePrivateKey: "Handle image sync node private key"
|
||||
ImageSyncHandlePublicKey: "Handle image sync node public key"
|
||||
ImageSyncTransfer: "Start transferring image temporary file: {{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
|
||||
|
||||
#mobile app
|
||||
ErrVerifyToken: 'トークンの検証エラーです。リセット後、再度QRコードをスキャンしてください。'
|
||||
ErrInvalidToken: '無効なトークンです。リセット後、再度QRコードをスキャンしてください。'
|
||||
|
||||
@@ -307,6 +307,25 @@ DBConnErr: "오류: 데이터베이스 연결 초기화 실패 {{ .err }}"
|
||||
SystemVersion: "버전: "
|
||||
SystemMode: "모드: "
|
||||
|
||||
#exchange
|
||||
LocalNodeIpFailed: "Failed to get master node IP. Edit the master node and add IP address and SSH authentication information."
|
||||
HandlePrivateKey: "Handle node private key"
|
||||
HandlePublicKey: "Handle node public key"
|
||||
ExchangeFile: "Start syncing {{ .sourcePath }} from node {{ .source }} to node {{ .dest }}:{{ .destPath }}"
|
||||
TaskRsync: "Sync"
|
||||
NodeFile: "Node file"
|
||||
ImageSyncTaskName: "Image sync {{ .source }} -> {{ .count }} nodes"
|
||||
ImageSyncSave: "Save image {{ .image }}"
|
||||
ImageSyncSaveTags: "Save image tags {{ .tags }}"
|
||||
ImageSyncToNode: "Sync image {{ .image }} to node {{ .node }}"
|
||||
ImageSyncLoad: "Load image {{ .image }} on node {{ .node }}"
|
||||
ImageSyncClean: "Clean temporary files for image {{ .image }}"
|
||||
ImageSyncNoTag: "Image {{ .image }} has no tag and will be saved by image ID"
|
||||
ImageSyncFrontendTagsIgnored: "No tags were found for image {{ .image }} on the source node. Frontend tags were ignored."
|
||||
ImageSyncHandlePrivateKey: "Handle image sync node private key"
|
||||
ImageSyncHandlePublicKey: "Handle image sync node public key"
|
||||
ImageSyncTransfer: "Start transferring image temporary file: {{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
|
||||
|
||||
#mobile app
|
||||
ErrVerifyToken: '토큰 검증 오류가 발생했습니다. 재설정 후 다시 스캔해 주세요.'
|
||||
ErrInvalidToken: '유효하지 않은 토큰입니다. 재설정 후 다시 스캔해 주세요.'
|
||||
|
||||
@@ -302,6 +302,25 @@ DBConnErr: "Ralat: Gagal memulakan sambungan pangkalan data, {{ .err }}"
|
||||
SystemVersion: "Versi: "
|
||||
SystemMode: "Mod: "
|
||||
|
||||
#exchange
|
||||
LocalNodeIpFailed: "Failed to get master node IP. Edit the master node and add IP address and SSH authentication information."
|
||||
HandlePrivateKey: "Handle node private key"
|
||||
HandlePublicKey: "Handle node public key"
|
||||
ExchangeFile: "Start syncing {{ .sourcePath }} from node {{ .source }} to node {{ .dest }}:{{ .destPath }}"
|
||||
TaskRsync: "Sync"
|
||||
NodeFile: "Node file"
|
||||
ImageSyncTaskName: "Image sync {{ .source }} -> {{ .count }} nodes"
|
||||
ImageSyncSave: "Save image {{ .image }}"
|
||||
ImageSyncSaveTags: "Save image tags {{ .tags }}"
|
||||
ImageSyncToNode: "Sync image {{ .image }} to node {{ .node }}"
|
||||
ImageSyncLoad: "Load image {{ .image }} on node {{ .node }}"
|
||||
ImageSyncClean: "Clean temporary files for image {{ .image }}"
|
||||
ImageSyncNoTag: "Image {{ .image }} has no tag and will be saved by image ID"
|
||||
ImageSyncFrontendTagsIgnored: "No tags were found for image {{ .image }} on the source node. Frontend tags were ignored."
|
||||
ImageSyncHandlePrivateKey: "Handle image sync node private key"
|
||||
ImageSyncHandlePublicKey: "Handle image sync node public key"
|
||||
ImageSyncTransfer: "Start transferring image temporary file: {{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
|
||||
|
||||
#cluster
|
||||
ErrMasterDelete: "Tidak dapat menghapus nod utama, sila hapuskan nod perantara dahulu."
|
||||
ClusterNameIsExist: "Nama kluster sudah wujud."
|
||||
|
||||
@@ -307,6 +307,25 @@ DBConnErr: "Erro: Falha ao inicializar a conexão com o banco de dados, {{ .err
|
||||
SystemVersion: "versão: "
|
||||
SystemMode: "modo: "
|
||||
|
||||
#exchange
|
||||
LocalNodeIpFailed: "Failed to get master node IP. Edit the master node and add IP address and SSH authentication information."
|
||||
HandlePrivateKey: "Handle node private key"
|
||||
HandlePublicKey: "Handle node public key"
|
||||
ExchangeFile: "Start syncing {{ .sourcePath }} from node {{ .source }} to node {{ .dest }}:{{ .destPath }}"
|
||||
TaskRsync: "Sync"
|
||||
NodeFile: "Node file"
|
||||
ImageSyncTaskName: "Image sync {{ .source }} -> {{ .count }} nodes"
|
||||
ImageSyncSave: "Save image {{ .image }}"
|
||||
ImageSyncSaveTags: "Save image tags {{ .tags }}"
|
||||
ImageSyncToNode: "Sync image {{ .image }} to node {{ .node }}"
|
||||
ImageSyncLoad: "Load image {{ .image }} on node {{ .node }}"
|
||||
ImageSyncClean: "Clean temporary files for image {{ .image }}"
|
||||
ImageSyncNoTag: "Image {{ .image }} has no tag and will be saved by image ID"
|
||||
ImageSyncFrontendTagsIgnored: "No tags were found for image {{ .image }} on the source node. Frontend tags were ignored."
|
||||
ImageSyncHandlePrivateKey: "Handle image sync node private key"
|
||||
ImageSyncHandlePublicKey: "Handle image sync node public key"
|
||||
ImageSyncTransfer: "Start transferring image temporary file: {{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
|
||||
|
||||
#mobile app
|
||||
ErrVerifyToken: 'Erro de verificação do token, por favor, reinicie e escaneie novamente.'
|
||||
ErrInvalidToken: 'Token inválido, por favor, reinicie e escaneie novamente.'
|
||||
|
||||
@@ -306,6 +306,25 @@ DBConnErr: "Ошибка: не удалось инициализировать
|
||||
SystemVersion: "Версия:"
|
||||
SystemMode: "Режим:"
|
||||
|
||||
#exchange
|
||||
LocalNodeIpFailed: "Failed to get master node IP. Edit the master node and add IP address and SSH authentication information."
|
||||
HandlePrivateKey: "Handle node private key"
|
||||
HandlePublicKey: "Handle node public key"
|
||||
ExchangeFile: "Start syncing {{ .sourcePath }} from node {{ .source }} to node {{ .dest }}:{{ .destPath }}"
|
||||
TaskRsync: "Sync"
|
||||
NodeFile: "Node file"
|
||||
ImageSyncTaskName: "Image sync {{ .source }} -> {{ .count }} nodes"
|
||||
ImageSyncSave: "Save image {{ .image }}"
|
||||
ImageSyncSaveTags: "Save image tags {{ .tags }}"
|
||||
ImageSyncToNode: "Sync image {{ .image }} to node {{ .node }}"
|
||||
ImageSyncLoad: "Load image {{ .image }} on node {{ .node }}"
|
||||
ImageSyncClean: "Clean temporary files for image {{ .image }}"
|
||||
ImageSyncNoTag: "Image {{ .image }} has no tag and will be saved by image ID"
|
||||
ImageSyncFrontendTagsIgnored: "No tags were found for image {{ .image }} on the source node. Frontend tags were ignored."
|
||||
ImageSyncHandlePrivateKey: "Handle image sync node private key"
|
||||
ImageSyncHandlePublicKey: "Handle image sync node public key"
|
||||
ImageSyncTransfer: "Start transferring image temporary file: {{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
|
||||
|
||||
#mobile app
|
||||
ErrVerifyToken: 'шибка проверки токена, пожалуйста, сбросьте и отсканируйте снова.'
|
||||
ErrInvalidToken: 'Неверный токен, пожалуйста, сбросьте и отсканируйте снова.'
|
||||
|
||||
@@ -306,6 +306,25 @@ DBConnErr: "Hata: Veritabanı bağlantısını başlatma başarısız, {{ .err }
|
||||
SystemVersion: "sürüm: "
|
||||
SystemMode: "mod: "
|
||||
|
||||
#exchange
|
||||
LocalNodeIpFailed: "Failed to get master node IP. Edit the master node and add IP address and SSH authentication information."
|
||||
HandlePrivateKey: "Handle node private key"
|
||||
HandlePublicKey: "Handle node public key"
|
||||
ExchangeFile: "Start syncing {{ .sourcePath }} from node {{ .source }} to node {{ .dest }}:{{ .destPath }}"
|
||||
TaskRsync: "Sync"
|
||||
NodeFile: "Node file"
|
||||
ImageSyncTaskName: "Image sync {{ .source }} -> {{ .count }} nodes"
|
||||
ImageSyncSave: "Save image {{ .image }}"
|
||||
ImageSyncSaveTags: "Save image tags {{ .tags }}"
|
||||
ImageSyncToNode: "Sync image {{ .image }} to node {{ .node }}"
|
||||
ImageSyncLoad: "Load image {{ .image }} on node {{ .node }}"
|
||||
ImageSyncClean: "Clean temporary files for image {{ .image }}"
|
||||
ImageSyncNoTag: "Image {{ .image }} has no tag and will be saved by image ID"
|
||||
ImageSyncFrontendTagsIgnored: "No tags were found for image {{ .image }} on the source node. Frontend tags were ignored."
|
||||
ImageSyncHandlePrivateKey: "Handle image sync node private key"
|
||||
ImageSyncHandlePublicKey: "Handle image sync node public key"
|
||||
ImageSyncTransfer: "Start transferring image temporary file: {{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
|
||||
|
||||
#mobile app
|
||||
ErrVerifyToken: 'Token doğrulama hatası, lütfen sıfırlayın ve tekrar tarayın.'
|
||||
ErrInvalidToken: 'Geçersiz token, lütfen sıfırlayın ve tekrar tarayın.'
|
||||
|
||||
@@ -316,6 +316,17 @@ HandlePublicKey: "處理節點公鑰"
|
||||
ExchangeFile: "開始從 {{ .source }} 節點同步 {{ .sourcePath }} 到 {{ .dest }} 節點 {{ .destPath }}"
|
||||
TaskRsync: "同步"
|
||||
NodeFile: "節點檔案"
|
||||
ImageSyncTaskName: "映像同步 {{ .source }} -> {{ .count }} 個節點"
|
||||
ImageSyncSave: "儲存映像 {{ .image }}"
|
||||
ImageSyncSaveTags: "儲存映像標籤 {{ .tags }}"
|
||||
ImageSyncToNode: "同步映像 {{ .image }} 到節點 {{ .node }}"
|
||||
ImageSyncLoad: "在節點 {{ .node }} 載入映像 {{ .image }}"
|
||||
ImageSyncClean: "清理映像 {{ .image }} 暫存檔案"
|
||||
ImageSyncNoTag: "映像 {{ .image }} 沒有標籤,將使用映像 ID 儲存"
|
||||
ImageSyncFrontendTagsIgnored: "映像 {{ .image }} 在來源節點未查詢到標籤,已忽略前端傳入標籤"
|
||||
ImageSyncHandlePrivateKey: "處理映像同步節點私鑰"
|
||||
ImageSyncHandlePublicKey: "處理映像同步節點公鑰"
|
||||
ImageSyncTransfer: "開始傳輸映像暫存檔案:{{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
|
||||
|
||||
#mobile app
|
||||
ErrVerifyToken: '令牌驗證錯誤,請重設後再次掃碼'
|
||||
|
||||
@@ -322,6 +322,17 @@ HandlePublicKey: "处理节点公钥"
|
||||
ExchangeFile: "开始从 {{ .source }} 节点同步 {{ .sourcePath }} 到 {{ .dest }} 节点 {{ .destPath }}"
|
||||
TaskRsync: "同步"
|
||||
NodeFile: "节点文件"
|
||||
ImageSyncTaskName: "镜像同步 {{ .source }} -> {{ .count }} 个节点"
|
||||
ImageSyncSave: "保存镜像 {{ .image }}"
|
||||
ImageSyncSaveTags: "保存镜像标签 {{ .tags }}"
|
||||
ImageSyncToNode: "同步镜像 {{ .image }} 到节点 {{ .node }}"
|
||||
ImageSyncLoad: "在节点 {{ .node }} 加载镜像 {{ .image }}"
|
||||
ImageSyncClean: "清理镜像 {{ .image }} 临时文件"
|
||||
ImageSyncNoTag: "镜像 {{ .image }} 没有标签,将使用镜像 ID 保存"
|
||||
ImageSyncFrontendTagsIgnored: "镜像 {{ .image }} 在源节点未查询到标签,已忽略前端传入标签"
|
||||
ImageSyncHandlePrivateKey: "处理镜像同步节点私钥"
|
||||
ImageSyncHandlePublicKey: "处理镜像同步节点公钥"
|
||||
ImageSyncTransfer: "开始传输镜像临时文件:{{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
|
||||
|
||||
#mobile app
|
||||
ErrVerifyToken: '令牌验证错误,请重置后再次扫码'
|
||||
|
||||
@@ -78,7 +78,7 @@ func LoadMenus() string {
|
||||
{ID: "113", Disabled: false, Title: "xpack.monitor.name", IsShow: true, Label: "MonitorDashboard", Path: "/xpack/monitor/dashboard", Sort: 500},
|
||||
{ID: "114", Disabled: false, Title: "xpack.tamper.tamper", IsShow: true, Label: "Tamper", Path: "/xpack/tamper", Sort: 600},
|
||||
{ID: "120", Disabled: false, Title: "xpack.cluster.cluster", IsShow: true, Label: "Cluster", Path: "/xpack/cluster", Sort: 700},
|
||||
{ID: "115", Disabled: false, Title: "xpack.exchange.exchange", IsShow: true, Label: "FileExange", Path: "/xpack/exchange/file", Sort: 800},
|
||||
{ID: "115", Disabled: false, Title: "xpack.sync.menu", IsShow: true, Label: "Sync", Path: "/xpack/sync", Sort: 800},
|
||||
{ID: "117", Disabled: false, Title: "xpack.setting.setting", IsShow: true, Label: "XSetting", Path: "/xpack/setting", Sort: 900},
|
||||
}},
|
||||
{ID: "12", Disabled: false, Title: "menu.logs", IsShow: true, Label: "Log-Menu", Path: "/logs", Sort: 1200},
|
||||
@@ -183,7 +183,7 @@ func MenuSort() []dto.MenuLabelSort {
|
||||
{Label: "MonitorDashboard", Sort: 500},
|
||||
{Label: "Tamper", Sort: 600},
|
||||
{Label: "Cluster", Sort: 700},
|
||||
{Label: "FileExange", Sort: 800},
|
||||
{Label: "Sync", Sort: 800},
|
||||
{Label: "XSetting", Sort: 900},
|
||||
{Label: "Log-Menu", Sort: 1200},
|
||||
{Label: "Setting-Menu", Sort: 1300},
|
||||
|
||||
@@ -43,6 +43,7 @@ func Init() {
|
||||
migrations.AddAIBenchmarkMenu,
|
||||
migrations.AddAIProxyMenu,
|
||||
migrations.AddSkillsHubMenu,
|
||||
migrations.UpdateXpackSyncMenu,
|
||||
migrations.AddOperationLogUser,
|
||||
migrations.AddLoginLogUser,
|
||||
migrations.AddAlertAuditUser,
|
||||
|
||||
@@ -1164,6 +1164,50 @@ var AddSkillsHubMenu = &gormigrate.Migration{
|
||||
},
|
||||
}
|
||||
|
||||
var UpdateXpackSyncMenu = &gormigrate.Migration{
|
||||
ID: "20260616-update-xpack-sync-menu",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
var menuJSON string
|
||||
if err := tx.Model(&model.Setting{}).Where("key = ?", "HideMenu").Pluck("value", &menuJSON).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if menuJSON == "" {
|
||||
menuJSON = helper.LoadMenus()
|
||||
}
|
||||
|
||||
var menus []dto.ShowMenu
|
||||
if err := json.Unmarshal([]byte(menuJSON), &menus); err != nil {
|
||||
return tx.Model(&model.Setting{}).
|
||||
Where("key = ?", "HideMenu").
|
||||
Update("value", helper.LoadMenus()).Error
|
||||
}
|
||||
|
||||
for i := range menus {
|
||||
if menus[i].Label != "Xpack-Menu" {
|
||||
continue
|
||||
}
|
||||
for j := range menus[i].Children {
|
||||
if menus[i].Children[j].ID != "115" && menus[i].Children[j].Label != "FileExange" {
|
||||
continue
|
||||
}
|
||||
menus[i].Children[j].Title = "xpack.sync.menu"
|
||||
menus[i].Children[j].Label = "Sync"
|
||||
menus[i].Children[j].Path = "/xpack/sync"
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
updatedJSON, err := json.Marshal(menus)
|
||||
if err != nil {
|
||||
return tx.Model(&model.Setting{}).
|
||||
Where("key = ?", "HideMenu").
|
||||
Update("value", helper.LoadMenus()).Error
|
||||
}
|
||||
return tx.Model(&model.Setting{}).Where("key = ?", "HideMenu").Update("value", string(updatedJSON)).Error
|
||||
},
|
||||
}
|
||||
|
||||
var AddUserManagementMenu = &gormigrate.Migration{
|
||||
ID: "20260415-add-user-management-menu",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
|
||||
@@ -208,6 +208,7 @@ export namespace App {
|
||||
dockerCompose: string;
|
||||
app: App.AppDetail;
|
||||
linkDB: boolean;
|
||||
resourceKeys?: string[];
|
||||
}
|
||||
|
||||
export interface AppInstalledOption {
|
||||
|
||||
@@ -120,8 +120,13 @@ export const DownloadFile = (params: Container.ContainerLogInfo) => {
|
||||
};
|
||||
|
||||
// image
|
||||
export const searchImage = (params: Container.ImageSearch) => {
|
||||
return http.post<ResPage<Container.ImageInfo>>(`/containers/image/search`, params);
|
||||
export const searchImage = (params: Container.ImageSearch, currentNode?: string) => {
|
||||
return http.post<ResPage<Container.ImageInfo>>(
|
||||
`/containers/image/search`,
|
||||
params,
|
||||
TimeoutEnum.T_60S,
|
||||
currentNode ? { CurrentNode: currentNode } : undefined,
|
||||
);
|
||||
};
|
||||
export const listAllImage = () => {
|
||||
return http.get<Array<Container.ImageInfo>>(`/containers/image/all`);
|
||||
|
||||
@@ -174,7 +174,6 @@
|
||||
|
||||
<OpDialog ref="opRef" @search="search" />
|
||||
<TaskLog ref="taskLogRef" @close="search" />
|
||||
<PushApp ref="pushAppRef" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -201,19 +200,15 @@ import TaskLog from '@/components/log/task/index.vue';
|
||||
import { routerToFileWithPath } from '@/utils/router';
|
||||
import { useGlobalStore } from '@/composables/useGlobalStore';
|
||||
import { mysqlArgs } from '@/views/cronjob/cronjob/helper';
|
||||
import { loadOptionalComponent } from '@/extensions/optional';
|
||||
const { currentNode } = useGlobalStore();
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const PushApp = defineAsyncComponent(() => loadOptionalComponent('/src/xpack/views/appstore/push-app/index.vue'));
|
||||
|
||||
const selects = ref<any>([]);
|
||||
const args = ref([]);
|
||||
const loading = ref();
|
||||
const opRef = ref();
|
||||
const taskLogRef = ref();
|
||||
const pushAppRef = ref();
|
||||
|
||||
const data = ref();
|
||||
const paginationConfig = reactive({
|
||||
@@ -457,21 +452,6 @@ const buttons = [
|
||||
onRecover(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.migrate'),
|
||||
disabled: (row: any) => {
|
||||
return row.size === 0 || row.status === 'Failed' || row.accountType !== 'LOCAL';
|
||||
},
|
||||
show: () => {
|
||||
return type.value === 'app';
|
||||
},
|
||||
click: (row: Backup.RecordInfo) => {
|
||||
pushAppRef.value.acceptParams({
|
||||
appInstallID: appInstallID.value,
|
||||
appBackupID: row.id,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.download'),
|
||||
disabled: (row: any) => {
|
||||
|
||||
@@ -5542,9 +5542,42 @@ const message = {
|
||||
setDefaultHelper: 'The theme color scheme is about to be restored to its initial state. Continue?',
|
||||
setHelper: 'The currently selected theme color scheme is about to be saved. Continue?',
|
||||
},
|
||||
exchange: {
|
||||
exchange: 'File Exchange',
|
||||
exchangeConfirm: "transfer the file/folder {1} from {0} node to {2} node's {3} directory?",
|
||||
sync: {
|
||||
menu: 'Resource Sync',
|
||||
file: 'File Exchange',
|
||||
fileSyncConfirm: 'Do you want to transfer file/folder {1} from node {0} to directory {3} on node {2}?',
|
||||
image: 'Image Exchange',
|
||||
imageBatchDesc: 'Select a source node and image first, then batch-transfer to multiple target nodes.',
|
||||
imageBatchConfirmPrefix: 'About to transfer {0} images to {1} nodes, for a total of {2} tasks.',
|
||||
|
||||
cert: 'Certificate Sync',
|
||||
certBatchDesc:
|
||||
'After selecting a source node, sync the specified certificate into the current panel environment.',
|
||||
certBatchConfirmPrefix: 'About to sync {0} certificates to {1} nodes, for a total of {2} tasks.',
|
||||
|
||||
app: 'Application Transfer',
|
||||
appBatchDesc:
|
||||
'Select the source node, application, and target nodes, then confirm resource dependencies and start the application transfer task.',
|
||||
appSelectedApp: 'Selected Application:',
|
||||
appPreviewTitle: 'Transfer Preview',
|
||||
appPreviewDesc: 'Confirm target nodes and dependent resources before starting the application transfer.',
|
||||
appDatabaseDependency: 'Database dependency',
|
||||
appResourceRequired: 'Select all required linked resources first.',
|
||||
appUnsupportedMultipleResources: 'Only apps with at most one linked resource can be migrated.',
|
||||
appUnsupportedResourceType:
|
||||
'Only apps with no resource dependency or a single MySQL, MariaDB, or PostgreSQL dependency can be migrated.',
|
||||
|
||||
targetTitle: 'Target nodes',
|
||||
targetDesc: 'The source node is excluded automatically. Choose one or more target nodes.',
|
||||
targetSearchPlaceholder: 'Search node name or address',
|
||||
noTargetNodes: 'No target nodes available',
|
||||
noSourceNode: 'Please select a source node first',
|
||||
reviewTargets: 'Target nodes',
|
||||
reviewEmpty: 'Please select resources and target nodes first',
|
||||
selectSourceFirst: 'Please select a source node first.',
|
||||
selectResourceFirst: 'Please select resources to sync first.',
|
||||
selectTargetFirst: 'Please select at least one target node.',
|
||||
submitSuccess: 'Sync task submitted.',
|
||||
},
|
||||
cluster: {
|
||||
cluster: 'Application High Availability',
|
||||
|
||||
@@ -5602,9 +5602,46 @@ const message = {
|
||||
setDefaultHelper: 'La paleta de colores volverá al estado inicial. ¿Continuar?',
|
||||
setHelper: 'Se guardará la paleta actual como tema. ¿Continuar?',
|
||||
},
|
||||
exchange: {
|
||||
exchange: 'Intercambio de archivos',
|
||||
exchangeConfirm: '¿Quieres transferir {1} de {0} a {2}:{3}?',
|
||||
sync: {
|
||||
menu: 'Sincronización de Recursos',
|
||||
file: 'Transferencia de archivos',
|
||||
fileSyncConfirm: '¿Transferir el archivo/carpeta {1} del nodo {0} al directorio {3} del nodo {2}?',
|
||||
|
||||
image: 'Transferencia de imágenes',
|
||||
imageBatchDesc:
|
||||
'Seleccione primero el nodo de origen y las imágenes de origen, luego elija los nodos de destino para reenviar.',
|
||||
imageBatchConfirmPrefix: 'Se enviarán {0} imágenes a {1} nodos, creando {2} tareas.',
|
||||
|
||||
cert: 'Sincronización de certificados',
|
||||
certBatchDesc:
|
||||
'Después de seleccionar el nodo de origen, los certificados especificados pueden sincronizarse con el entorno actual del panel.',
|
||||
certBatchConfirmPrefix: 'Se sincronizarán {0} certificados a {1} nodos, creando {2} tareas.',
|
||||
|
||||
app: 'Transferencia de Aplicaciones',
|
||||
appBatchDesc:
|
||||
'Seleccione el nodo de origen, la aplicación y los nodos de destino, luego confirme las dependencias de recursos y ejecute la tarea de transferencia de aplicaciones.',
|
||||
appSelectedApp: 'Aplicación seleccionada:',
|
||||
appPreviewTitle: 'Vista previa de transferencia',
|
||||
appPreviewDesc:
|
||||
'Confirme los nodos de destino y los recursos dependientes antes de iniciar la transferencia de aplicaciones.',
|
||||
appDatabaseDependency: 'Dependencia de base de datos',
|
||||
appResourceRequired: 'Seleccione primero todos los recursos asociados requeridos.',
|
||||
appUnsupportedMultipleResources:
|
||||
'Actualmente solo se admite la migración de aplicaciones asociadas con un máximo de un recurso.',
|
||||
appUnsupportedResourceType:
|
||||
'Actualmente solo se admite la migración de aplicaciones sin dependencias de recursos o que dependan únicamente de MySQL, MariaDB o PostgreSQL.',
|
||||
|
||||
targetTitle: 'Nodos de destino',
|
||||
targetDesc: 'El nodo de origen se excluye automáticamente. Puede seleccionar uno o más nodos de destino.',
|
||||
targetSearchPlaceholder: 'Buscar nombre o dirección del nodo',
|
||||
noTargetNodes: 'No hay nodos de destino disponibles',
|
||||
noSourceNode: 'Seleccione primero un nodo de origen',
|
||||
reviewTargets: 'Nodos de destino',
|
||||
reviewEmpty: 'Seleccione primero los recursos y los nodos de destino',
|
||||
selectSourceFirst: 'Seleccione primero un nodo de origen.',
|
||||
selectResourceFirst: 'Seleccione primero un recurso para sincronizar.',
|
||||
selectTargetFirst: 'Seleccione al menos un nodo de destino.',
|
||||
submitSuccess: 'La tarea de sincronización se ha enviado correctamente.',
|
||||
},
|
||||
cluster: {
|
||||
cluster: 'Alta disponibilidad de aplicaciones',
|
||||
|
||||
@@ -5577,9 +5577,43 @@ const message = {
|
||||
setDefaultHelper: 'テーマカラーを初期状態に戻そうとしています。続行しますか?',
|
||||
setHelper: '現在選択されているテーマカラーを保存しようとしています。続行しますか?',
|
||||
},
|
||||
exchange: {
|
||||
exchange: 'ファイル交換',
|
||||
exchangeConfirm: '{0} ノードのファイル/フォルダ {1} を {2} ノードの {3} ディレクトリに転送しますか?',
|
||||
sync: {
|
||||
menu: 'リソース同期',
|
||||
file: 'ファイル転送',
|
||||
fileSyncConfirm: 'ノード {0} のファイル/フォルダ {1} をノード {2} のディレクトリ {3} に転送しますか?',
|
||||
|
||||
image: 'イメージ転送',
|
||||
imageBatchDesc: 'まずソースノードとソースイメージを選択し、その後転送先ノードを選択してください。',
|
||||
imageBatchConfirmPrefix:
|
||||
'{0} 個のイメージを {1} 個のノードへ転送します。合計 {2} 件のタスクが作成されます。',
|
||||
|
||||
cert: '証明書同期',
|
||||
certBatchDesc: 'ソースノードを選択すると、指定した証明書を現在のパネル環境へ同期できます。',
|
||||
certBatchConfirmPrefix: '{0} 件の証明書を {1} 個のノードへ同期します。合計 {2} 件のタスクが作成されます。',
|
||||
|
||||
app: 'アプリ転送',
|
||||
appBatchDesc:
|
||||
'ソースノード、アプリケーション、ターゲットノードを選択し、リソース依存関係を確認してアプリ転送タスクを実行します。',
|
||||
appSelectedApp: '選択したアプリ:',
|
||||
appPreviewTitle: '転送プレビュー',
|
||||
appPreviewDesc: 'ターゲットノードと依存リソースを確認してからアプリ転送を実行してください。',
|
||||
appDatabaseDependency: 'データベース依存関係',
|
||||
appResourceRequired: '必要な関連リソースをすべて選択してください。',
|
||||
appUnsupportedMultipleResources: '現在、関連リソースが最大1つのアプリのみ移行できます。',
|
||||
appUnsupportedResourceType:
|
||||
'現在、リソース依存がないアプリ、または MySQL・MariaDB・PostgreSQL のみを利用するアプリのみ移行できます。',
|
||||
|
||||
targetTitle: 'ターゲットノード',
|
||||
targetDesc: 'ソースノードは自動的に除外されます。1つ以上のターゲットノードを選択できます。',
|
||||
targetSearchPlaceholder: 'ノード名またはアドレスを検索',
|
||||
noTargetNodes: '利用可能なターゲットノードがありません',
|
||||
noSourceNode: 'まずソースノードを選択してください',
|
||||
reviewTargets: 'ターゲットノード',
|
||||
reviewEmpty: 'まずリソースとターゲットノードを選択してください',
|
||||
selectSourceFirst: 'まずソースノードを選択してください。',
|
||||
selectResourceFirst: 'まず同期するリソースを選択してください。',
|
||||
selectTargetFirst: '少なくとも1つのターゲットノードを選択してください。',
|
||||
submitSuccess: '同期タスクが送信されました。',
|
||||
},
|
||||
cluster: {
|
||||
cluster: 'アプリケーションの高可用性',
|
||||
|
||||
@@ -5462,9 +5462,43 @@ const message = {
|
||||
setDefaultHelper: '테마 색상 스킴이 초기 상태로 복원됩니다. 계속하시겠습니까?',
|
||||
setHelper: '현재 선택한 테마 색상 스킴이 저장됩니다. 계속하시겠습니까?',
|
||||
},
|
||||
exchange: {
|
||||
exchange: '파일 교환',
|
||||
exchangeConfirm: '{0} 노드의 파일/폴더 {1}을(를) {2} 노드의 {3} 디렉토리로 전송하시겠습니까?',
|
||||
sync: {
|
||||
menu: '리소스 동기화',
|
||||
file: '파일 전송',
|
||||
fileSyncConfirm: '{0} 노드의 파일/폴더 {1}을(를) {2} 노드의 디렉터리 {3}(으)로 전송하시겠습니까?',
|
||||
|
||||
image: '이미지 전송',
|
||||
imageBatchDesc: '먼저 원본 노드와 원본 이미지를 선택한 후 대상 노드를 선택하여 전달합니다.',
|
||||
imageBatchConfirmPrefix: '{0}개의 이미지를 {1}개 노드로 전달합니다. 총 {2}개의 작업이 생성됩니다.',
|
||||
|
||||
cert: '인증서 동기화',
|
||||
certBatchDesc: '원본 노드를 선택한 후 지정된 인증서를 현재 패널 환경으로 동기화할 수 있습니다.',
|
||||
certBatchConfirmPrefix: '{0}개의 인증서를 {1}개 노드로 동기화합니다. 총 {2}개의 작업이 생성됩니다.',
|
||||
|
||||
app: '애플리케이션 전송',
|
||||
appBatchDesc:
|
||||
'원본 노드, 애플리케이션 및 대상 노드를 선택한 후 리소스 종속성을 확인하고 애플리케이션 전송 작업을 실행합니다.',
|
||||
appSelectedApp: '선택한 애플리케이션:',
|
||||
appPreviewTitle: '전송 미리보기',
|
||||
appPreviewDesc: '대상 노드와 종속 리소스를 확인한 후 애플리케이션 전송을 실행하세요.',
|
||||
appDatabaseDependency: '데이터베이스 종속성',
|
||||
appResourceRequired: '필수 연관 리소스를 모두 먼저 선택하세요.',
|
||||
appUnsupportedMultipleResources:
|
||||
'현재 최대 하나의 리소스만 연결된 애플리케이션만 마이그레이션할 수 있습니다.',
|
||||
appUnsupportedResourceType:
|
||||
'현재 리소스 종속성이 없거나 MySQL, MariaDB, PostgreSQL에만 의존하는 애플리케이션만 마이그레이션할 수 있습니다.',
|
||||
|
||||
targetTitle: '대상 노드',
|
||||
targetDesc: '원본 노드는 자동으로 제외됩니다. 하나 이상의 대상 노드를 선택할 수 있습니다.',
|
||||
targetSearchPlaceholder: '노드 이름 또는 주소 검색',
|
||||
noTargetNodes: '선택 가능한 대상 노드가 없습니다',
|
||||
noSourceNode: '먼저 원본 노드를 선택하세요',
|
||||
reviewTargets: '대상 노드',
|
||||
reviewEmpty: '먼저 리소스와 대상 노드를 선택하세요',
|
||||
selectSourceFirst: '먼저 원본 노드를 선택하세요.',
|
||||
selectResourceFirst: '먼저 동기화할 리소스를 선택하세요.',
|
||||
selectTargetFirst: '최소 하나의 대상 노드를 선택하세요.',
|
||||
submitSuccess: '동기화 작업이 제출되었습니다.',
|
||||
},
|
||||
cluster: {
|
||||
cluster: '애플리케이션 고가용성',
|
||||
|
||||
@@ -5649,9 +5649,46 @@ const message = {
|
||||
setDefaultHelper: 'Skema warna tema akan dipulihkan ke keadaan asalnya. Adakah anda ingin meneruskan?',
|
||||
setHelper: 'Skema warna tema yang dipilih sekarang akan disimpan. Adakah anda ingin meneruskan?',
|
||||
},
|
||||
exchange: {
|
||||
exchange: 'Pertukaran Fail',
|
||||
exchangeConfirm: 'Adakah anda mahu memindahkan fail/folder {1} dari node {0} ke direktori {3} node {2}?',
|
||||
sync: {
|
||||
menu: 'Penyegerakan Sumber',
|
||||
file: 'Pemindahan Fail',
|
||||
fileSyncConfirm: 'Pindahkan fail/folder {1} dari nod {0} ke direktori {3} pada nod {2}?',
|
||||
|
||||
image: 'Pemindahan Imej',
|
||||
imageBatchDesc:
|
||||
'Pilih nod sumber dan imej sumber terlebih dahulu, kemudian pilih nod sasaran untuk pemindahan.',
|
||||
imageBatchConfirmPrefix: 'Akan memindahkan {0} imej ke {1} nod, dengan jumlah {2} tugasan.',
|
||||
|
||||
cert: 'Penyegerakan Sijil',
|
||||
certBatchDesc:
|
||||
'Selepas memilih nod sumber, sijil yang ditentukan boleh disegerakkan ke persekitaran panel semasa.',
|
||||
certBatchConfirmPrefix: 'Akan menyegerakkan {0} sijil ke {1} nod, dengan jumlah {2} tugasan.',
|
||||
|
||||
app: 'Pemindahan Aplikasi',
|
||||
appBatchDesc:
|
||||
'Pilih nod sumber, aplikasi dan nod sasaran, kemudian sahkan kebergantungan sumber dan jalankan tugas pemindahan aplikasi.',
|
||||
appSelectedApp: 'Aplikasi Dipilih:',
|
||||
appPreviewTitle: 'Pratonton Pemindahan',
|
||||
appPreviewDesc: 'Sahkan nod sasaran dan sumber bergantung sebelum memulakan pemindahan aplikasi.',
|
||||
appDatabaseDependency: 'Kebergantungan Pangkalan Data',
|
||||
appResourceRequired: 'Sila pilih semua sumber berkaitan yang diperlukan terlebih dahulu.',
|
||||
appUnsupportedMultipleResources:
|
||||
'Pada masa ini, hanya aplikasi yang dikaitkan dengan maksimum satu sumber boleh dipindahkan.',
|
||||
appUnsupportedResourceType:
|
||||
'Pada masa ini, hanya aplikasi tanpa kebergantungan sumber atau yang bergantung pada MySQL, MariaDB atau PostgreSQL sahaja boleh dipindahkan.',
|
||||
|
||||
targetTitle: 'Nod Sasaran',
|
||||
targetDesc:
|
||||
'Nod sumber akan dikecualikan secara automatik. Anda boleh memilih satu atau lebih nod sasaran.',
|
||||
targetSearchPlaceholder: 'Cari nama atau alamat nod',
|
||||
noTargetNodes: 'Tiada nod sasaran tersedia',
|
||||
noSourceNode: 'Sila pilih nod sumber terlebih dahulu',
|
||||
reviewTargets: 'Nod Sasaran',
|
||||
reviewEmpty: 'Sila pilih sumber dan nod sasaran terlebih dahulu',
|
||||
selectSourceFirst: 'Sila pilih nod sumber terlebih dahulu.',
|
||||
selectResourceFirst: 'Sila pilih sumber untuk disegerakkan terlebih dahulu.',
|
||||
selectTargetFirst: 'Sila pilih sekurang-kurangnya satu nod sasaran.',
|
||||
submitSuccess: 'Tugas penyegerakan berjaya dihantar.',
|
||||
},
|
||||
cluster: {
|
||||
cluster: 'Aplikasi Tinggi Ketersediaan',
|
||||
|
||||
@@ -5796,9 +5796,46 @@ const message = {
|
||||
setDefaultHelper: 'O esquema de cores do tema será restaurado para o estado inicial. Deseja continuar?',
|
||||
setHelper: 'O esquema de cores do tema selecionado será salvo. Deseja continuar?',
|
||||
},
|
||||
exchange: {
|
||||
exchange: 'Troca de Arquivos',
|
||||
exchangeConfirm: 'Deseja transferir o arquivo/pasta {1} do nó {0} para o diretório {3} do nó {2}?',
|
||||
sync: {
|
||||
menu: 'Sincronização de Recursos',
|
||||
file: 'Transferência de Arquivos',
|
||||
fileSyncConfirm: 'Transferir o arquivo/pasta {1} do nó {0} para o diretório {3} no nó {2}?',
|
||||
|
||||
image: 'Transferência de Imagens',
|
||||
imageBatchDesc:
|
||||
'Selecione primeiro o nó de origem e as imagens de origem e, em seguida, escolha os nós de destino para encaminhamento.',
|
||||
imageBatchConfirmPrefix: 'Serão encaminhadas {0} imagens para {1} nós, totalizando {2} tarefas.',
|
||||
|
||||
cert: 'Sincronização de Certificados',
|
||||
certBatchDesc:
|
||||
'Após selecionar o nó de origem, os certificados especificados podem ser sincronizados com o ambiente atual do painel.',
|
||||
certBatchConfirmPrefix: 'Serão sincronizados {0} certificados para {1} nós, totalizando {2} tarefas.',
|
||||
|
||||
app: 'Transferência de Aplicativos',
|
||||
appBatchDesc:
|
||||
'Selecione o nó de origem, o aplicativo e os nós de destino, confirme as dependências de recursos e execute a tarefa de transferência de aplicativos.',
|
||||
appSelectedApp: 'Aplicativo Selecionado:',
|
||||
appPreviewTitle: 'Prévia da Transferência',
|
||||
appPreviewDesc:
|
||||
'Confirme os nós de destino e os recursos dependentes antes de iniciar a transferência do aplicativo.',
|
||||
appDatabaseDependency: 'Dependência de Banco de Dados',
|
||||
appResourceRequired: 'Selecione primeiro todos os recursos associados obrigatórios.',
|
||||
appUnsupportedMultipleResources:
|
||||
'Atualmente, apenas aplicativos associados a no máximo um recurso podem ser migrados.',
|
||||
appUnsupportedResourceType:
|
||||
'Atualmente, apenas aplicativos sem dependências de recursos ou dependentes apenas de MySQL, MariaDB ou PostgreSQL podem ser migrados.',
|
||||
|
||||
targetTitle: 'Nós de Destino',
|
||||
targetDesc: 'O nó de origem será excluído automaticamente. Você pode selecionar um ou mais nós de destino.',
|
||||
targetSearchPlaceholder: 'Pesquisar nome ou endereço do nó',
|
||||
noTargetNodes: 'Nenhum nó de destino disponível',
|
||||
noSourceNode: 'Selecione primeiro um nó de origem',
|
||||
reviewTargets: 'Nós de Destino',
|
||||
reviewEmpty: 'Selecione primeiro os recursos e os nós de destino',
|
||||
selectSourceFirst: 'Selecione primeiro um nó de origem.',
|
||||
selectResourceFirst: 'Selecione primeiro um recurso para sincronizar.',
|
||||
selectTargetFirst: 'Selecione pelo menos um nó de destino.',
|
||||
submitSuccess: 'Tarefa de sincronização enviada com sucesso.',
|
||||
},
|
||||
cluster: {
|
||||
cluster: 'Alta Disponibilidade de Aplicações',
|
||||
|
||||
@@ -5648,9 +5648,45 @@ const message = {
|
||||
setDefaultHelper: 'Цветовая схема темы будет восстановлена до исходного состояния. Вы хотите продолжить?',
|
||||
setHelper: 'Выбранная в данный момент цветовая схема темы будет сохранена. Вы хотите продолжить?',
|
||||
},
|
||||
exchange: {
|
||||
exchange: 'Обмен файлами',
|
||||
exchangeConfirm: 'Хотите перенести файл/папку {1} с узла {0} в каталог {3} узла {2}?',
|
||||
sync: {
|
||||
menu: 'Синхронизация ресурсов',
|
||||
file: 'Передача файлов',
|
||||
fileSyncConfirm: 'Передать файл/папку {1} с узла {0} в каталог {3} на узле {2}?',
|
||||
|
||||
image: 'Передача образов',
|
||||
imageBatchDesc:
|
||||
'Сначала выберите исходный узел и исходные образы, затем выберите целевые узлы для передачи.',
|
||||
imageBatchConfirmPrefix: 'Будет передано {0} образов на {1} узлов, всего {2} задач.',
|
||||
|
||||
cert: 'Синхронизация сертификатов',
|
||||
certBatchDesc:
|
||||
'После выбора исходного узла указанные сертификаты можно синхронизировать с текущей средой панели.',
|
||||
certBatchConfirmPrefix: 'Будет синхронизировано {0} сертификатов на {1} узлов, всего {2} задач.',
|
||||
|
||||
app: 'Передача приложений',
|
||||
appBatchDesc:
|
||||
'Выберите исходный узел, приложение и целевые узлы, подтвердите зависимости ресурсов и запустите задачу передачи приложения.',
|
||||
appSelectedApp: 'Выбранное приложение:',
|
||||
appPreviewTitle: 'Предварительный просмотр передачи',
|
||||
appPreviewDesc: 'Подтвердите целевые узлы и зависимые ресурсы перед запуском передачи приложения.',
|
||||
appDatabaseDependency: 'Зависимость базы данных',
|
||||
appResourceRequired: 'Сначала выберите все необходимые связанные ресурсы.',
|
||||
appUnsupportedMultipleResources:
|
||||
'В настоящее время поддерживается миграция только приложений, связанных максимум с одним ресурсом.',
|
||||
appUnsupportedResourceType:
|
||||
'В настоящее время поддерживается миграция только приложений без зависимостей ресурсов или зависящих только от MySQL, MariaDB или PostgreSQL.',
|
||||
|
||||
targetTitle: 'Целевые узлы',
|
||||
targetDesc: 'Исходный узел будет автоматически исключён. Можно выбрать один или несколько целевых узлов.',
|
||||
targetSearchPlaceholder: 'Поиск по имени или адресу узла',
|
||||
noTargetNodes: 'Нет доступных целевых узлов',
|
||||
noSourceNode: 'Сначала выберите исходный узел',
|
||||
reviewTargets: 'Целевые узлы',
|
||||
reviewEmpty: 'Сначала выберите ресурсы и целевые узлы',
|
||||
selectSourceFirst: 'Сначала выберите исходный узел.',
|
||||
selectResourceFirst: 'Сначала выберите ресурс для синхронизации.',
|
||||
selectTargetFirst: 'Выберите хотя бы один целевой узел.',
|
||||
submitSuccess: 'Задача синхронизации успешно отправлена.',
|
||||
},
|
||||
cluster: {
|
||||
cluster: 'Высокая доступность приложений',
|
||||
|
||||
@@ -5639,9 +5639,43 @@ const message = {
|
||||
setDefaultHelper: 'Tema renk şeması başlangıç durumuna geri yüklenecek. Devam etmek istiyor musunuz?',
|
||||
setHelper: 'Seçilen tema renk şeması kaydedilecek. Devam etmek istiyor musunuz?',
|
||||
},
|
||||
exchange: {
|
||||
exchange: 'Dosya Değişimi',
|
||||
exchangeConfirm: '{0} düğümünden {1} dosya/klasörünü {2} düğümünün {3} dizinine aktarmak istiyor musunuz?',
|
||||
sync: {
|
||||
menu: 'Kaynak Senkronizasyonu',
|
||||
file: 'Dosya Aktarımı',
|
||||
fileSyncConfirm: '{0} düğümündeki {1} dosya/klasörü {2} düğümündeki {3} dizinine aktarmak istiyor musunuz?',
|
||||
|
||||
image: 'İmaj Aktarımı',
|
||||
imageBatchDesc: 'Önce kaynak düğümü ve kaynak imajları seçin, ardından iletim için hedef düğümleri seçin.',
|
||||
imageBatchConfirmPrefix: '{0} imaj {1} düğüme aktarılacak, toplam {2} görev oluşturulacak.',
|
||||
|
||||
cert: 'Sertifika Senkronizasyonu',
|
||||
certBatchDesc:
|
||||
'Kaynak düğüm seçildikten sonra belirtilen sertifikalar mevcut panel ortamına senkronize edilebilir.',
|
||||
certBatchConfirmPrefix: '{0} sertifika {1} düğüme senkronize edilecek, toplam {2} görev oluşturulacak.',
|
||||
|
||||
app: 'Uygulama Aktarımı',
|
||||
appBatchDesc:
|
||||
'Kaynak düğümü, uygulamayı ve hedef düğümleri seçin, ardından kaynak bağımlılıklarını doğrulayarak uygulama aktarım görevini başlatın.',
|
||||
appSelectedApp: 'Seçilen Uygulama:',
|
||||
appPreviewTitle: 'Aktarım Önizlemesi',
|
||||
appPreviewDesc: 'Uygulama aktarımını başlatmadan önce hedef düğümleri ve bağımlı kaynakları doğrulayın.',
|
||||
appDatabaseDependency: 'Veritabanı Bağımlılığı',
|
||||
appResourceRequired: 'Lütfen önce gerekli tüm ilişkili kaynakları seçin.',
|
||||
appUnsupportedMultipleResources: 'Şu anda yalnızca en fazla bir kaynakla ilişkili uygulamalar taşınabilir.',
|
||||
appUnsupportedResourceType:
|
||||
'Şu anda yalnızca kaynak bağımlılığı olmayan veya yalnızca MySQL, MariaDB ya da PostgreSQL kullanan uygulamalar taşınabilir.',
|
||||
|
||||
targetTitle: 'Hedef Düğümler',
|
||||
targetDesc: 'Kaynak düğüm otomatik olarak hariç tutulur. Bir veya daha fazla hedef düğüm seçebilirsiniz.',
|
||||
targetSearchPlaceholder: 'Düğüm adı veya adres ara',
|
||||
noTargetNodes: 'Kullanılabilir hedef düğüm yok',
|
||||
noSourceNode: 'Lütfen önce bir kaynak düğüm seçin',
|
||||
reviewTargets: 'Hedef Düğümler',
|
||||
reviewEmpty: 'Lütfen önce kaynakları ve hedef düğümleri seçin',
|
||||
selectSourceFirst: 'Lütfen önce bir kaynak düğüm seçin.',
|
||||
selectResourceFirst: 'Lütfen önce senkronize edilecek kaynağı seçin.',
|
||||
selectTargetFirst: 'Lütfen en az bir hedef düğüm seçin.',
|
||||
submitSuccess: 'Senkronizasyon görevi başarıyla gönderildi.',
|
||||
},
|
||||
cluster: {
|
||||
cluster: 'Высокая доступность приложений',
|
||||
|
||||
@@ -5181,9 +5181,40 @@ const message = {
|
||||
qrCodeExpired: '重新整理時間',
|
||||
apiLeakageHelper: '請勿洩露二維碼,確保僅在受信任的環境中使用',
|
||||
},
|
||||
exchange: {
|
||||
exchange: '檔案對傳',
|
||||
exchangeConfirm: '是否將 {0} 節點檔案/資料夾 {1} 傳輸到 {2} 節點 {3} 目錄?',
|
||||
sync: {
|
||||
menu: '資源同步',
|
||||
file: '檔案對傳',
|
||||
fileSyncConfirm: '是否將 {0} 節點檔案/資料夾 {1} 傳輸到 {2} 節點 {3} 目錄?',
|
||||
|
||||
image: '映像對傳',
|
||||
imageBatchDesc: '先選擇來源節點和來源映像,再批次選擇目標節點進行轉發。',
|
||||
imageBatchConfirmPrefix: '即將把 {0} 張映像轉發到 {1} 個節點,共 {2} 個任務。',
|
||||
|
||||
cert: '證書同步',
|
||||
certBatchDesc: '選擇來源節點後,可將指定證書同步到目前面板環境。',
|
||||
certBatchConfirmPrefix: '即將把 {0} 張證書同步到 {1} 個節點,共 {2} 個任務。',
|
||||
|
||||
app: '應用對傳',
|
||||
appBatchDesc: '選擇來源節點、單個應用和目標節點後,確認資源依賴並執行應用對傳任務。',
|
||||
appSelectedApp: '已選應用:',
|
||||
appPreviewTitle: '對傳預覽',
|
||||
appPreviewDesc: '確認目標節點和依賴資源後執行應用對傳。',
|
||||
appDatabaseDependency: '資料庫依賴',
|
||||
appResourceRequired: '請先選擇所有必需的關聯資源。',
|
||||
appUnsupportedMultipleResources: '目前僅支援遷移最多關聯一個資源的應用。',
|
||||
appUnsupportedResourceType: '目前僅支援遷移無資源依賴或僅依賴 MySQL、MariaDB、PostgreSQL 的應用。',
|
||||
|
||||
targetTitle: '目標節點',
|
||||
targetDesc: '來源節點會自動排除,可選擇一個或多個目標節點。',
|
||||
targetSearchPlaceholder: '搜尋節點名稱或位址',
|
||||
noTargetNodes: '沒有可選目標節點',
|
||||
noSourceNode: '請先選擇來源節點',
|
||||
reviewTargets: '目標節點',
|
||||
reviewEmpty: '請先選擇資源和目標節點',
|
||||
selectSourceFirst: '請先選擇來源節點。',
|
||||
selectResourceFirst: '請先選擇要同步的資源。',
|
||||
selectTargetFirst: '請先選擇至少一個目標節點。',
|
||||
submitSuccess: '同步任務已提交。',
|
||||
},
|
||||
cluster: {
|
||||
cluster: '應用高可用',
|
||||
|
||||
@@ -5157,9 +5157,40 @@ const message = {
|
||||
qrCodeExpired: '刷新时间',
|
||||
apiLeakageHelper: '请勿泄露二维码,确保仅在受信任的环境中使用',
|
||||
},
|
||||
exchange: {
|
||||
exchange: '文件对传',
|
||||
exchangeConfirm: '是否将 {0} 节点文件/文件夹 {1} 传输到 {2} 节点 {3} 目录?',
|
||||
sync: {
|
||||
menu: '资源同步',
|
||||
file: '文件对传',
|
||||
fileSyncConfirm: '是否将 {0} 节点文件/文件夹 {1} 传输到 {2} 节点 {3} 目录?',
|
||||
|
||||
image: '镜像对传',
|
||||
imageBatchDesc: '先选择源节点和源镜像,再批量选择目标节点进行转发。',
|
||||
imageBatchConfirmPrefix: '即将把 {0} 张镜像转发到 {1} 个节点,共 {2} 个任务。',
|
||||
|
||||
cert: '证书同步',
|
||||
certBatchDesc: '选择源节点后,可将指定证书同步到当前面板环境。',
|
||||
certBatchConfirmPrefix: '即将把 {0} 张证书同步到 {1} 个节点,共 {2} 个任务。',
|
||||
|
||||
app: '应用对传',
|
||||
appBatchDesc: '选择源节点、单个应用和目标节点后,确认资源依赖并执行应用对传任务。',
|
||||
appSelectedApp: '已选应用:',
|
||||
appPreviewTitle: '对传预览',
|
||||
appPreviewDesc: '确认目标节点和依赖资源后执行应用对传。',
|
||||
appDatabaseDependency: '数据库依赖',
|
||||
appResourceRequired: '请先选择所有必需的关联资源。',
|
||||
appUnsupportedMultipleResources: '当前仅支持迁移最多关联一个资源的应用。',
|
||||
appUnsupportedResourceType: '当前仅支持迁移无资源依赖或仅依赖 MySQL、MariaDB、PostgreSQL 的应用。',
|
||||
|
||||
targetTitle: '目标节点',
|
||||
targetDesc: '源节点会自动排除,可选择一个或多个目标节点。',
|
||||
targetSearchPlaceholder: '搜索节点名称或地址',
|
||||
noTargetNodes: '没有可选目标节点',
|
||||
noSourceNode: '请先选择源节点',
|
||||
reviewTargets: '目标节点',
|
||||
reviewEmpty: '请先选择资源和目标节点',
|
||||
selectSourceFirst: '请先选择源节点。',
|
||||
selectResourceFirst: '请先选择要同步的资源。',
|
||||
selectTargetFirst: '请先选择至少一个目标节点。',
|
||||
submitSuccess: '同步任务已提交。',
|
||||
},
|
||||
cluster: {
|
||||
cluster: '应用高可用',
|
||||
|
||||
Reference in New Issue
Block a user