diff --git a/agent/app/service/ai_gateway_recover.go b/agent/app/service/ai_gateway_recover.go new file mode 100644 index 000000000..3abfcd4a4 --- /dev/null +++ b/agent/app/service/ai_gateway_recover.go @@ -0,0 +1,63 @@ +package service + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/1Panel-dev/1Panel/agent/app/model" + "github.com/1Panel-dev/1Panel/agent/buserr" + "github.com/1Panel-dev/1Panel/agent/global" + "github.com/1Panel-dev/1Panel/agent/utils/files" +) + +func prepareAIGatewayAppRecover(install *model.AppInstall, recoverFile, secret string) (string, func(), error) { + noop := func() {} + if !isAIGatewayApp(install.App.Key) { + return "", noop, nil + } + tmpDir, err := os.MkdirTemp(global.Dir.TmpDir, "ai-gateway-recover-") + if err != nil { + return "", noop, err + } + cleanup := func() { _ = os.RemoveAll(tmpDir) } + fail := func(err error) (string, func(), error) { + cleanup() + return "", noop, err + } + if err := files.NewFileOp().TarGzExtractPro(recoverFile, tmpDir, secret); err != nil { + return fail(err) + } + backupDir := filepath.Join(tmpDir, strings.ReplaceAll(filepath.Base(recoverFile), ".tar.gz", "")) + for _, name := range []string{"app.json", "app.tar.gz"} { + info, err := os.Lstat(filepath.Join(backupDir, name)) + if err != nil || !info.Mode().IsRegular() { + return fail(buserr.New("AppBackupFileIncomplete")) + } + } + metadata, err := os.ReadFile(filepath.Join(backupDir, "app.json")) + if err != nil { + return fail(err) + } + var backup model.AppInstall + if err := json.Unmarshal(metadata, &backup); err != nil { + return fail(fmt.Errorf("unmarshal app.json failed: %w", err)) + } + if backup.App.Key != install.App.Key || backup.Name != install.Name { + return fail(buserr.New("AppAttributesNotMatch")) + } + // Historical backups already include Version. Unsuffixed releases are + // SQLite; no new metadata field is required. Missing versions are invalid, + // not evidence that an archive contains SQLite data. + if strings.TrimSpace(backup.Version) == "" || strings.TrimSpace(install.Version) == "" { + return fail(buserr.New("AppBackupFileIncomplete")) + } + // Deliberately do not compare version order: restoring an older version of + // the same database type is required for failed-upgrade rollbacks. + if !isAIGatewayUpgradeVersionAllowed(install.App.Key, install.Version, backup.Version) { + return fail(buserr.New("ErrAIGatewayRecoverDatabaseTypeMismatch")) + } + return backupDir, cleanup, nil +} diff --git a/agent/app/service/ai_gateway_upgrade.go b/agent/app/service/ai_gateway_upgrade.go new file mode 100644 index 000000000..b15b85178 --- /dev/null +++ b/agent/app/service/ai_gateway_upgrade.go @@ -0,0 +1,37 @@ +package service + +import ( + "sort" + "strings" + + "github.com/1Panel-dev/1Panel/agent/utils/common" +) + +const aiGatewayAppKey = "ai-gateway" + +func isAIGatewayApp(appKey string) bool { + return appKey == aiGatewayAppKey || appKey == "local"+aiGatewayAppKey +} + +func isAIGatewayPostgresVersion(version string) bool { + return strings.HasSuffix(version, "-pg") || strings.HasSuffix(version, "-postgres") +} + +// Database variants are deployment choices, not interchangeable upgrades. +func isAIGatewayUpgradeVersionAllowed(appKey, currentVersion, targetVersion string) bool { + return !isAIGatewayApp(appKey) || + isAIGatewayPostgresVersion(currentVersion) == isAIGatewayPostgresVersion(targetVersion) +} + +func sortAIGatewayVersions(versions []string) { + sort.SliceStable(versions, func(i, j int) bool { + if common.CompareVersion(versions[i], versions[j]) { + return true + } + if common.CompareVersion(versions[j], versions[i]) { + return false + } + // Prefer SQLite only when the numeric versions are equal. + return !isAIGatewayPostgresVersion(versions[i]) && isAIGatewayPostgresVersion(versions[j]) + }) +} diff --git a/agent/app/service/app_install.go b/agent/app/service/app_install.go index 18f33e2db..4cda319c0 100644 --- a/agent/app/service/app_install.go +++ b/agent/app/service/app_install.go @@ -687,6 +687,9 @@ func (a *AppInstallService) GetUpdateVersions(req request.AppUpdateVersion) ([]d if !canAccessVllmVersion(app.Key, detail.Version) { continue } + if !isAIGatewayUpgradeVersionAllowed(app.Key, install.Version, detail.Version) { + continue + } ignores, _ := appIgnoreUpgradeRepo.List(runtimeRepo.WithDetailId(detail.ID), appIgnoreUpgradeRepo.WithScope("version")) if len(ignores) > 0 { continue diff --git a/agent/app/service/app_upgrade.go b/agent/app/service/app_upgrade.go index 373e8da13..2ba5d3075 100644 --- a/agent/app/service/app_upgrade.go +++ b/agent/app/service/app_upgrade.go @@ -106,6 +106,9 @@ func upgradeInstall(req request.AppInstallUpgrade) error { if err != nil { return err } + if !isAIGatewayUpgradeVersionAllowed(install.App.Key, install.Version, detail.Version) { + return buserr.New("ErrAIGatewayDatabaseTypeMismatch") + } if err = checkVllmVersionAccess(install.App.Key, detail.Version); err != nil { return err } diff --git a/agent/app/service/app_utils.go b/agent/app/service/app_utils.go index 9dfd7c9ae..065a4cb40 100644 --- a/agent/app/service/app_utils.go +++ b/agent/app/service/app_utils.go @@ -1571,6 +1571,9 @@ func handleInstalled(appInstallList []model.AppInstall, updated, sync, checkUpda var versions []string for _, appDetail := range details { + if !isAIGatewayUpgradeVersionAllowed(installed.App.Key, installed.Version, appDetail.Version) { + continue + } ignores, _ := appIgnoreUpgradeRepo.List(runtimeRepo.WithDetailId(appDetail.ID), appIgnoreUpgradeRepo.WithScope("version")) if len(ignores) > 0 { continue @@ -2279,7 +2282,12 @@ func getAppVersions(key string, details []model.AppDetail) []string { } versionsRaw = append(versionsRaw, detail.Version) } - versions = common.GetSortedVersions(versionsRaw) + if isAIGatewayApp(key) { + sortAIGatewayVersions(versionsRaw) + versions = versionsRaw + } else { + versions = common.GetSortedVersions(versionsRaw) + } if hasLatest { versions = append([]string{latestVersion}, versions...) } diff --git a/agent/app/service/backup_app.go b/agent/app/service/backup_app.go index 361fb7252..714bd9ae9 100644 --- a/agent/app/service/backup_app.go +++ b/agent/app/service/backup_app.go @@ -132,11 +132,9 @@ func (u *BackupService) AppRecover(req dto.CommonRecover) error { if !fileOp.Stat(req.File) { return buserr.WithName("ErrFileNotFound", req.File) } - if _, err := compose.Down(install.GetComposePath()); err != nil { - return err - } if err := handleAppRecover(&install, nil, req.File, false, req.Secret, req.TaskID); err != nil { global.LOG.Errorf("recover app %s failed, err: %v", req.DetailName, err) + return err } return nil } @@ -200,8 +198,20 @@ func handleAppBackup(install *model.AppInstall, parentTask *task.Task, recordID } func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverFile string, isRollback bool, secret, taskID string) error { + // Validate AI Gateway backups before stopping the app, creating rollback + // backups, or touching its files/database. Keep the validated extraction for + // the restore so uploaded/encrypted archives are not unpacked twice. + preparedPath, cleanup, err := prepareAIGatewayAppRecover(install, recoverFile, secret) + if err != nil { + return err + } + if parentTask == nil && !isRollback { + if _, err := compose.Down(install.GetComposePath()); err != nil { + cleanup() + return err + } + } var ( - err error recoverTask *task.Task isOk = false rollbackFile string @@ -210,11 +220,13 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF if parentTask == nil { recoverTask, err = task.NewTaskWithOps(install.Name, task.TaskRecover, task.TaskScopeBackup, taskID, install.ID) if err != nil { + cleanup() return err } } recoverApp := func(t *task.Task) error { + defer cleanup() fileOp := files.NewFileOp() if !isRollback { rollbackFile = path.Join(global.Dir.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format(constant.DateTimeSlimLayout))) @@ -223,10 +235,13 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF } } - if err := fileOp.TarGzExtractPro(recoverFile, path.Dir(recoverFile), secret); err != nil { - return err + tmpPath := preparedPath + if tmpPath == "" { + if err := fileOp.TarGzExtractPro(recoverFile, path.Dir(recoverFile), secret); err != nil { + return err + } + tmpPath = strings.ReplaceAll(recoverFile, ".tar.gz", "") } - tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "") if err := fileOp.TarGzExtractPro(tmpPath+"/app.tar.gz", tmpPath, ""); err != nil { return err } @@ -236,7 +251,7 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF } else { _, _ = compose.Up(install.GetComposePath()) } - _ = os.RemoveAll(strings.ReplaceAll(recoverFile, ".tar.gz", "")) + _ = os.RemoveAll(tmpPath) }() if !fileOp.Stat(tmpPath+"/app.json") || !fileOp.Stat(tmpPath+"/app.tar.gz") { @@ -397,6 +412,7 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF } recoverTask.AddSubTask(task.GetTaskName(install.Name, task.TaskRecover, task.TaskScopeBackup), recoverApp, rollBackApp) go func() { + defer cleanup() _ = recoverTask.Execute() }() return nil diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml index ded8cd878..eba7ac597 100644 --- a/agent/i18n/lang/en.yaml +++ b/agent/i18n/lang/en.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Unable to derive a project name from Docker Compose ErrComposeNameInvalid: 'Invalid Compose project name: it must start with a lowercase letter or number, contain only lowercase letters, numbers, hyphens, and underscores, and be 1-256 characters long.' ErrAppVersionUnavailable: 'This application version has been removed from the remote service. Please select another version and try again.' ErrVllmGB10ProOnly: 'This vLLM version is available only in 1Panel Professional Edition.' +ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway can only upgrade within the same database type (SQLite or PostgreSQL).' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'The AI Gateway backup and target application must use the same database type (SQLite or PostgreSQL).' ErrAppWarn: 'App status abnormal; check logs' ErrAppParamKey: 'Invalid app parameter: {{ .name }}' ErrAppUpgrade: 'App upgrade failed: {{ .name }} {{ .err }}' diff --git a/agent/i18n/lang/es-ES.yaml b/agent/i18n/lang/es-ES.yaml index 17d3243ae..b2830488c 100644 --- a/agent/i18n/lang/es-ES.yaml +++ b/agent/i18n/lang/es-ES.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'No se pudo derivar un nombre de proyecto desde la c ErrComposeNameInvalid: 'Nombre de proyecto Compose no válido: debe comenzar con una letra minúscula o un número, contener solo letras minúsculas, números, guiones y guiones bajos, y tener entre 1 y 256 caracteres.' ErrAppVersionUnavailable: 'Esta versión de la aplicación se ha eliminado del servicio remoto. Seleccione otra versión e inténtelo de nuevo.' ErrVllmGB10ProOnly: 'Esta versión de vLLM solo está disponible en 1Panel Professional Edition.' +ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway solo puede actualizarse dentro del mismo tipo de base de datos (SQLite o PostgreSQL).' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'La copia de seguridad de AI Gateway y la aplicación de destino deben usar el mismo tipo de base de datos (SQLite o PostgreSQL).' ErrAppWarn: 'Estado anómalo, revise el log' ErrAppParamKey: 'El campo de parámetro {{ .name }} es anómalo' ErrAppUpgrade: 'La actualización de la aplicación {{ .name }} falló {{ .err }}' diff --git a/agent/i18n/lang/fa.yaml b/agent/i18n/lang/fa.yaml index c6dd515b7..3490e80e8 100644 --- a/agent/i18n/lang/fa.yaml +++ b/agent/i18n/lang/fa.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'نام پروژه از پیکربندی Docker Comp ErrComposeNameInvalid: 'نام پروژه Compose نامعتبر است: باید با حرف کوچک یا عدد شروع شود، فقط شامل حروف کوچک، اعداد، خط تیره و زیرخط باشد و ۱ تا ۲۵۶ نویسه داشته باشد.' ErrAppVersionUnavailable: 'این نسخه برنامه از سرویس راه دور حذف شده است. لطفاً نسخه دیگری را انتخاب کرده و دوباره تلاش کنید.' ErrVllmGB10ProOnly: 'این نسخه vLLM فقط در نسخه حرفه‌ای 1Panel در دسترس است.' +ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway فقط در همان نوع پایگاه داده (SQLite یا PostgreSQL) قابل ارتقا است.' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'نسخه پشتیبان AI Gateway و برنامه مقصد باید از یک نوع پایگاه داده (SQLite یا PostgreSQL) استفاده کنند.' ErrAppWarn: 'وضعیت برنامه غیرعادی است؛ لاگ‌ها را بررسی کنید' ErrAppParamKey: 'پارامتر برنامه نامعتبر است: {{ .name }}' ErrAppUpgrade: 'ارتقاء برنامه ناموفق بود: {{ .name }} {{ .err }}' diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml index 56e719e3b..7f14a3ceb 100644 --- a/agent/i18n/lang/ja.yaml +++ b/agent/i18n/lang/ja.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Docker Compose 設定またはファイルの親デ ErrComposeNameInvalid: 'Compose プロジェクト名の形式が正しくありません。小文字または数字で始まり、小文字、数字、ハイフン、アンダースコアのみを使用した 1~256 文字にしてください。' ErrAppVersionUnavailable: '現在のアプリケーションバージョンはリモートサービスから削除されています。別のバージョンを選択して再試行してください。' ErrVllmGB10ProOnly: 'この vLLM バージョンは 1Panel プロフェッショナル版でのみ利用できます。' +ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway は同じデータベース種別(SQLite または PostgreSQL)間でのみアップグレードできます。' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'AI Gateway のバックアップと復元先アプリのデータベース種別(SQLite または PostgreSQL)は一致している必要があります。' ErrAppWarn: '異常な状態です。ログを確認してください' ErrAppParamKey: 'パラメータ {{ .name }} フィールドが異常です' ErrAppUpgrade: 'アプリケーション {{ .name }} のアップグレードに失敗しました {{ .err }}' diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml index 1a1df4adc..886d06a44 100644 --- a/agent/i18n/lang/ko.yaml +++ b/agent/i18n/lang/ko.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Docker Compose 구성 또는 파일의 상위 디 ErrComposeNameInvalid: 'Compose 프로젝트 이름 형식이 잘못되었습니다. 소문자 또는 숫자로 시작하고 소문자, 숫자, 하이픈, 밑줄만 사용하여 1~256자로 입력하세요.' ErrAppVersionUnavailable: '현재 애플리케이션 버전이 원격 서비스에서 제거되었습니다. 다른 버전을 선택한 후 다시 시도해 주세요.' ErrVllmGB10ProOnly: '이 vLLM 버전은 1Panel 프로페셔널 에디션에서만 사용할 수 있습니다.' +ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway는 동일한 데이터베이스 유형(SQLite 또는 PostgreSQL) 내에서만 업그레이드할 수 있습니다.' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'AI Gateway 백업과 대상 애플리케이션의 데이터베이스 유형(SQLite 또는 PostgreSQL)이 같아야 합니다.' ErrAppWarn: '비정상적인 상태입니다. 로그를 확인해 주세요.' ErrAppParamKey: '매개변수 {{ .name }} 필드가 비정상입니다.' ErrAppUpgrade: '애플리케이션 {{ .name }} 업그레이드에 실패했습니다 {{ .err }}' diff --git a/agent/i18n/lang/lo.yaml b/agent/i18n/lang/lo.yaml index 61e79e983..d6dab51c4 100644 --- a/agent/i18n/lang/lo.yaml +++ b/agent/i18n/lang/lo.yaml @@ -130,6 +130,8 @@ ErrComposeProjectNameEmpty: 'ບໍ່ສາມາດກຳນົດຊື່ໂ ErrComposeNameInvalid: 'ຊື່ໂຄງການ Compose ບໍ່ຖືກຕ້ອງ: ຕ້ອງເລີ່ມດ້ວຍຕົວພິມນ້ອຍ ຫຼື ຕົວເລກ, ໃຊ້ໄດ້ສະເພາະຕົວພິມນ້ອຍ, ຕົວເລກ, ຂີດກາງ ແລະ ຂີດລຸ່ມ, ຄວາມຍາວ 1-256 ຕົວອັກສອນ.' ErrAppVersionUnavailable: 'ເວີຊັນແອັບນີ້ຖືກລຶບອອກຈາກບໍລິການທາງໄກແລ້ວ ກະລຸນາເລືອກເວີຊັນອື່ນແລ້ວລອງໃໝ່' ErrVllmGB10ProOnly: 'ເວີຊັນ vLLM ນີ້ມີໃຫ້ໃຊ້ສະເພາະໃນ 1Panel Professional Edition ເທົ່ານັ້ນ.' +ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway ສາມາດອັບເກຣດໄດ້ພາຍໃນປະເພດຖານຂໍ້ມູນດຽວກັນເທົ່ານັ້ນ (SQLite ຫຼື PostgreSQL).' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'ຂໍ້ມູນສຳຮອງ AI Gateway ແລະ ແອັບເປົ້າໝາຍຕ້ອງໃຊ້ປະເພດຖານຂໍ້ມູນດຽວກັນ (SQLite ຫຼື PostgreSQL).' ErrAppWarn: 'ສະຖານະແອັບຜິດປົກກະຕິ; ກະລຸນາກວດສອບບັນທຶກ' ErrAppParamKey: 'ພາຣາມິເຕີຂອງແອັບບໍ່ຖືກຕ້ອງ: {{ .name }}' ErrAppUpgrade: 'ອັບເກຣດແອັບລົ້ມເຫຼວ: {{ .name }} {{ .err }}' diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml index dcd298788..29325a51d 100644 --- a/agent/i18n/lang/ms.yaml +++ b/agent/i18n/lang/ms.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Nama projek tidak dapat diperoleh daripada konfigur ErrComposeNameInvalid: 'Nama projek Compose tidak sah: mesti bermula dengan huruf kecil atau nombor, hanya mengandungi huruf kecil, nombor, tanda sempang dan garis bawah, serta sepanjang 1-256 aksara.' ErrAppVersionUnavailable: 'Versi aplikasi ini telah dialih keluar daripada perkhidmatan jauh. Sila pilih versi lain dan cuba lagi.' ErrVllmGB10ProOnly: 'Versi vLLM ini hanya tersedia dalam 1Panel Edisi Profesional.' +ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway hanya boleh dinaik taraf dalam jenis pangkalan data yang sama (SQLite atau PostgreSQL).' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'Sandaran AI Gateway dan aplikasi sasaran mesti menggunakan jenis pangkalan data yang sama (SQLite atau PostgreSQL).' ErrAppWarn: 'Status tidak normal, sila semak log' ErrAppParamKey: 'Parameter {{ .name }} medan tidak normal' ErrAppUpgrade: 'Peningkatan {{ .name }} aplikasi gagal {{ .err }}' diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml index 41d03a15a..d02a01d1d 100644 --- a/agent/i18n/lang/pt-BR.yaml +++ b/agent/i18n/lang/pt-BR.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Não foi possível derivar um nome de projeto da co ErrComposeNameInvalid: 'Nome de projeto Compose inválido: deve começar com uma letra minúscula ou número, conter apenas letras minúsculas, números, hífens e sublinhados e ter de 1 a 256 caracteres.' ErrAppVersionUnavailable: 'Esta versão do aplicativo foi removida do serviço remoto. Selecione outra versão e tente novamente.' ErrVllmGB10ProOnly: 'Esta versão do vLLM está disponível apenas no 1Panel Professional Edition.' +ErrAIGatewayDatabaseTypeMismatch: 'O AI Gateway só pode ser atualizado dentro do mesmo tipo de banco de dados (SQLite ou PostgreSQL).' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'O backup do AI Gateway e o aplicativo de destino devem usar o mesmo tipo de banco de dados (SQLite ou PostgreSQL).' ErrAppWarn: 'Status anormal, verifique o log' ErrAppParamKey: 'O campo de parâmetro {{ .name }} está anormal' ErrAppUpgrade: 'Falha na atualização do aplicativo {{ .name }} {{ .err }}' diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml index ceb19a527..b099b411d 100644 --- a/agent/i18n/lang/ru.yaml +++ b/agent/i18n/lang/ru.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Не удалось получить имя про ErrComposeNameInvalid: 'Недопустимое имя проекта Compose: оно должно начинаться со строчной буквы или цифры, содержать только строчные буквы, цифры, дефисы и подчёркивания и иметь длину от 1 до 256 символов.' ErrAppVersionUnavailable: 'Эта версия приложения удалена из удаленного сервиса. Выберите другую версию и повторите попытку.' ErrVllmGB10ProOnly: 'Эта версия vLLM доступна только в профессиональной редакции 1Panel.' +ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway можно обновлять только в пределах одного типа базы данных (SQLite или PostgreSQL).' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'Резервная копия AI Gateway и целевое приложение должны использовать один и тот же тип базы данных (SQLite или PostgreSQL).' ErrAppWarn: 'Ненормальное состояние, проверьте журнал' ErrAppParamKey: 'Поле параметра {{ .name }} ненормально' ErrAppUpgrade: 'Обновление приложения {{ .name }} не удалось {{ .err }}' diff --git a/agent/i18n/lang/tr.yaml b/agent/i18n/lang/tr.yaml index 235e94598..42be12028 100644 --- a/agent/i18n/lang/tr.yaml +++ b/agent/i18n/lang/tr.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Docker Compose yapılandırmasından veya dosyanın ErrComposeNameInvalid: 'Geçersiz Compose proje adı: küçük harf veya rakamla başlamalı, yalnızca küçük harf, rakam, kısa çizgi ve alt çizgi içermeli ve 1-256 karakter uzunluğunda olmalıdır.' ErrAppVersionUnavailable: 'Bu uygulama sürümü uzak hizmetten kaldırıldı. Lütfen başka bir sürüm seçip tekrar deneyin.' ErrVllmGB10ProOnly: 'Bu vLLM sürümü yalnızca 1Panel Professional Edition sürümünde kullanılabilir.' +ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway yalnızca aynı veritabanı türü (SQLite veya PostgreSQL) içinde yükseltilebilir.' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'AI Gateway yedeği ve hedef uygulama aynı veritabanı türünü (SQLite veya PostgreSQL) kullanmalıdır.' ErrAppWarn: 'Anormal durum, lütfen günlüğü kontrol edin' ErrAppParamKey: 'Parametre {{ .name }} alanı anormal' ErrAppUpgrade: 'Uygulama {{ .name }} yükseltmesi başarısız {{ .err }}' diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml index e37663cbf..cdbbf7a6b 100644 --- a/agent/i18n/lang/zh-Hant.yaml +++ b/agent/i18n/lang/zh-Hant.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: '無法從 Docker Compose 設定或檔案父目錄 ErrComposeNameInvalid: 'Compose 專案名稱格式錯誤:必須以小寫字母或數字開頭,僅支援小寫字母、數字、- 和 _,長度為 1-256 個字元' ErrAppVersionUnavailable: '目前應用程式版本已從遠端服務下架,請選擇其他版本後重試' ErrVllmGB10ProOnly: '此 vLLM 版本僅支援 1Panel 專業版' +ErrAIGatewayDatabaseTypeMismatch: 'AI 閘道只能在相同資料庫類型(SQLite 或 PostgreSQL)之間升級。' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'AI 閘道備份與目標應用程式的資料庫類型(SQLite 或 PostgreSQL)必須一致,無法跨資料庫類型還原。' ErrAppWarn: '狀態異常,請檢視日誌' ErrAppParamKey: '參數{{ .name }} 欄位異常' ErrAppUpgrade: '應用程式{{ .name }} 升級失敗{{ .err }}' diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml index 911b88d4d..11764017e 100644 --- a/agent/i18n/lang/zh.yaml +++ b/agent/i18n/lang/zh.yaml @@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: "无法从 Docker Compose 配置或文件父目录 ErrComposeNameInvalid: "Compose 项目名称格式错误:必须以小写字母或数字开头,仅支持小写字母、数字、- 和 _,长度为 1-256 个字符" ErrAppVersionUnavailable: "当前应用版本已从远程服务下架,请选择其他版本后重试" ErrVllmGB10ProOnly: "该 vLLM 版本仅支持 1Panel 专业版" +ErrAIGatewayDatabaseTypeMismatch: 'AI 网关只能在相同数据库类型(SQLite 或 PostgreSQL)之间升级。' +ErrAIGatewayRecoverDatabaseTypeMismatch: 'AI 网关备份与目标应用的数据库类型(SQLite 或 PostgreSQL)必须一致,无法跨数据库类型恢复。' ErrAppWarn: "状态异常,请查看日志" ErrAppParamKey: "参数 {{ .name }} 字段异常" ErrAppUpgrade: "应用 {{ .name }} 升级失败 {{ .err }}" diff --git a/frontend/package.json b/frontend/package.json index e4846a03e..4c31c1e88 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -102,5 +102,9 @@ "monaco-editor": { "dompurify": "3.4.16" } + }, + "allowScripts": { + "@vue-office/docx@1.6.3": true, + "@vue-office/excel@1.7.14": true } }