diff --git a/agent/app/api/v2/dashboard.go b/agent/app/api/v2/dashboard.go index adfc353ed..5816da449 100644 --- a/agent/app/api/v2/dashboard.go +++ b/agent/app/api/v2/dashboard.go @@ -32,7 +32,7 @@ func (b *BaseApi) LoadDashboardOsInfo(c *gin.Context) { // @Security Timestamp // @Router /dashboard/app/launcher [get] func (b *BaseApi) LoadAppLauncher(c *gin.Context) { - data, err := dashboardService.LoadAppLauncher() + data, err := dashboardService.LoadAppLauncher(c) if err != nil { helper.InternalServer(c, err) return diff --git a/agent/app/dto/dashboard.go b/agent/app/dto/dashboard.go index 6ccf14ae7..45d25d721 100644 --- a/agent/app/dto/dashboard.go +++ b/agent/app/dto/dashboard.go @@ -140,9 +140,8 @@ type AppLauncher struct { Name string `json:"name"` Icon string `json:"icon"` Limit int `json:"limit"` - ShortDescZh string `json:"shortDescZh"` - ShortDescEn string `json:"shortDescEn"` - Recommend int `json:"recomend"` + Description string `json:"description"` + Recommend int `json:"recommend"` IsInstall bool `json:"isInstall"` IsRecommend bool `json:"isRecommend"` diff --git a/agent/app/service/dashboard.go b/agent/app/service/dashboard.go index 6ceae4a55..268587e2f 100644 --- a/agent/app/service/dashboard.go +++ b/agent/app/service/dashboard.go @@ -21,6 +21,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/common" "github.com/1Panel-dev/1Panel/agent/utils/copier" + "github.com/gin-gonic/gin" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/host" @@ -37,7 +38,7 @@ type IDashboardService interface { LoadCurrentInfoForNode() *dto.NodeCurrent LoadCurrentInfo(ioOption string, netOption string) *dto.DashboardCurrent - LoadAppLauncher() ([]dto.AppLauncher, error) + LoadAppLauncher(ctx *gin.Context) ([]dto.AppLauncher, error) ChangeShow(req dto.SettingUpdate) error ListLauncherOption(filter string) ([]dto.LauncherOption, error) Restart(operation string) error @@ -263,7 +264,7 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d return ¤tInfo } -func (u *DashboardService) LoadAppLauncher() ([]dto.AppLauncher, error) { +func (u *DashboardService) LoadAppLauncher(ctx *gin.Context) ([]dto.AppLauncher, error) { var ( data []dto.AppLauncher recommendList []dto.AppLauncher @@ -289,9 +290,8 @@ func (u *DashboardService) LoadAppLauncher() ([]dto.AppLauncher, error) { itemData.Name = app.Name itemData.Icon = app.Icon itemData.Limit = app.Limit - itemData.ShortDescEn = app.ShortDescEn - itemData.ShortDescZh = app.ShortDescZh itemData.Recommend = app.Recommend + itemData.Description = app.GetDescription(ctx) break } } diff --git a/agent/app/service/snapshot_create.go b/agent/app/service/snapshot_create.go index c290bed40..55e6ed244 100644 --- a/agent/app/service/snapshot_create.go +++ b/agent/app/service/snapshot_create.go @@ -283,6 +283,11 @@ func snapBaseData(snap snapHelper, targetDir string) error { if err != nil { return err } + err = snap.FileOp.CopyFile("/usr/local/bin/1pctl", targetDir) + snap.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/usr/local/bin/1pctl"), err) + if err != nil { + return err + } } err := snap.FileOp.CopyFile("/usr/local/bin/1panel-agent", targetDir) @@ -291,12 +296,6 @@ func snapBaseData(snap snapHelper, targetDir string) error { return err } - err = snap.FileOp.CopyFile("/usr/local/bin/1pctl", targetDir) - snap.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/usr/local/bin/1pctl"), err) - if err != nil { - return err - } - if global.IsMaster { err = snap.FileOp.CopyFile("/etc/systemd/system/1panel-core.service", targetDir) snap.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/etc/systemd/system/1panel-core.service"), err) diff --git a/agent/app/service/snapshot_recover.go b/agent/app/service/snapshot_recover.go index d62144ab0..878c7b641 100644 --- a/agent/app/service/snapshot_recover.go +++ b/agent/app/service/snapshot_recover.go @@ -246,12 +246,12 @@ func backupBeforeRecover(name string, itemHelper *snapRecoverHelper) error { } } - err = itemHelper.FileOp.CopyFile("/usr/local/bin/1pctl", baseDir) - itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/usr/local/bin/1pctl"), err) - if err != nil { - return err - } if global.IsMaster { + err = itemHelper.FileOp.CopyFile("/usr/local/bin/1pctl", baseDir) + itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/usr/local/bin/1pctl"), err) + if err != nil { + return err + } err = itemHelper.FileOp.CopyFile("/usr/local/bin/1panel-core", baseDir) itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/usr/local/bin/1panel-core"), err) if err != nil { @@ -328,13 +328,12 @@ func recoverBaseData(src string, itemHelper *snapRecoverHelper) error { itemHelper.Task.Log("---------------------- 6 / 10 ----------------------") itemHelper.Task.LogStart(i18n.GetMsgByKey("SnapBaseInfo")) - err := itemHelper.FileOp.CopyFile(path.Join(src, "1pctl"), "/usr/local/bin") - itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/usr/local/bin/1pctl"), err) - if err != nil { - return err - } - if global.IsMaster { + err := itemHelper.FileOp.CopyFile(path.Join(src, "1pctl"), "/usr/local/bin") + itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/usr/local/bin/1pctl"), err) + if err != nil { + return err + } err = itemHelper.FileOp.CopyFile(path.Join(src, "1panel-core"), "/usr/local/bin") itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/usr/local/bin/1panel-core"), err) if err != nil { @@ -346,7 +345,7 @@ func recoverBaseData(src string, itemHelper *snapRecoverHelper) error { return err } } - err = itemHelper.FileOp.CopyFile(path.Join(src, "1panel-agent"), "/usr/local/bin") + err := itemHelper.FileOp.CopyFile(path.Join(src, "1panel-agent"), "/usr/local/bin") itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/usr/local/bin/1panel-agent"), err) if err != nil { return err diff --git a/frontend/src/components/license-import/index.vue b/frontend/src/components/license-import/index.vue index 85911f9ae..c9e18ddfd 100644 --- a/frontend/src/components/license-import/index.vue +++ b/frontend/src/components/license-import/index.vue @@ -25,6 +25,9 @@ +
+ {{ $t('license.updateForce') }} +
(); const uploaderFiles = ref([]); const isImport = ref(); +const isForce = ref(); const oldLicense = ref(); interface DialogProps { @@ -109,6 +113,7 @@ const submit = async () => { if (!isImport.value) { formData.append('currentNode', globalStore.currentNode); } + formData.append('isForce', isForce.value); loading.value = true; await uploadLicense(oldLicense.value, formData) .then(async () => { diff --git a/frontend/src/components/port-jump/index.vue b/frontend/src/components/port-jump/index.vue index 9008dd155..57dcfd1c4 100644 --- a/frontend/src/components/port-jump/index.vue +++ b/frontend/src/components/port-jump/index.vue @@ -21,6 +21,8 @@ import i18n from '@/lang'; import { MsgError, MsgWarning } from '@/utils/message'; import { jumpToPath } from '@/utils/util'; import { useRouter } from 'vue-router'; +import { GlobalStore } from '@/store'; +const globalStore = GlobalStore(); const router = useRouter(); const open = ref(); @@ -39,8 +41,12 @@ const acceptParams = async (params: DialogProps): Promise => { let protocol = params.protocol === 'https' ? 'https' : 'http'; const res = await getAgentSettingInfo(); if (!res.data.systemIP) { - open.value = true; - return; + if (!globalStore.currentNodeAddr) { + open.value = true; + return; + } else { + res.data.systemIP = globalStore.currentNodeAddr; + } } if (res.data.systemIP.indexOf(':') === -1) { if (params.ip && params.ip === 'ipv6') { diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index a3b81d606..fa7fd127e 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -602,7 +602,9 @@ const message = { containerConnHelper: 'This connection address is used by applications running on the PHP execution environment/container installation.', remoteConn: 'External Connection', - remoteConnHelper2: 'Use this address for non-container or external connections', + remoteConnHelper2: 'Use this address for non-container environments or external connections.', + remoteConnHelper3: + 'The default access address is the host IP. To modify it, go to the "Default Access Address" configuration item in the panel settings page.', localIP: 'Local IP', }, aiTools: { @@ -1922,6 +1924,7 @@ const message = { forceUnbind: 'Force Unbind', forceUnbindHelper: 'Forcing unbind will ignore any errors that occur during the unbinding process and ultimately release the license binding.', + updateForce: 'Force update (ignore all errors during unbinding to ensure final operation succeeds)', trialInfo: 'Version', authorizationId: 'Authorization ID', authorizedUser: 'Authorized User', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index e583159db..94a803e1d 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -590,8 +590,9 @@ const message = { containerConnHelper: 'この接続アドレスは、Webサイトのランタイム(PHPなど)またはコンテナで実行されているアプリケーションで使用できます。', remoteConn: '外部接続', - remoteConnHelper2: - 'この接続アドレスは、非コンテナまたは外部アプリケーションで実行されているアプリケーションで使用できます。', + remoteConnHelper2: 'コンテナ環境以外または外部接続にはこのアドレスを使用してください。', + remoteConnHelper3: + 'デフォルトアクセスアドレスはホストIPです。変更するには、パネル設定ページの「デフォルトアクセスアドレス」設定項目へ移動してください。', localIP: 'ローカルIP', }, aiTools: { @@ -1831,6 +1832,7 @@ const message = { forceUnbind: '強制バインド解除', forceUnbindHelper: '強制的にバインド解除を行うと、解除プロセス中に発生するエラーを無視し、最終的にライセンスのバインドを解除します。', + updateForce: '強制更新(アンバインド中のすべてのエラーを無視し、最終操作の成功を保証します)', trialInfo: 'バージョン', authorizationId: 'サブスクリプション承認ID', authorizedUser: '認定ユーザー', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index ead596094..7c21f3fa0 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -587,8 +587,9 @@ const message = { containerConnHelper: '이 연결 주소는 웹사이트 런타임(PHP 등) 또는 컨테이너에서 실행 중인 애플리케이션에서 사용할 수 있습니다.', remoteConn: '외부 연결', - remoteConnHelper2: - '이 연결 주소는 컨테이너 외부 또는 외부 애플리케이션에서 실행 중인 애플리케이션에서 사용할 수 있습니다.', + remoteConnHelper2: '컨테이너 환경이 아닌 경우 또는 외부 연결에는 이 주소를 사용하십시오.', + remoteConnHelper3: + '기본 접근 주소는 호스트 IP입니다. 수정하려면 패널 설정 페이지의 "기본 접근 주소" 구성 항목으로 이동하세요.', localIP: '로컬 IP', }, aiTools: { @@ -1801,6 +1802,7 @@ const message = { forceUnbind: '강제 바인딩 해제', forceUnbindHelper: '강제 바인딩 해제를 수행하면 해제 과정에서 발생하는 오류를 무시하고 궁극적으로 라이센스 바인딩을 해제합니다.', + updateForce: '강제 업데이트 (바인딩 해제 과정의 모든 오류를 무시하고 최종 작업 성공을 보장합니다)', trialInfo: '버전', authorizationId: '구독 인증 ID', authorizedUser: '인증된 사용자', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index fc3f85e78..5c235436a 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -602,8 +602,9 @@ const message = { containerConnHelper: 'Alamat sambungan ini boleh digunakan oleh aplikasi yang berjalan pada runtime laman web (PHP, dll.) atau kontena.', remoteConn: 'Sambungan luaran', - remoteConnHelper2: - 'Alamat sambungan ini boleh digunakan oleh aplikasi yang berjalan di luar kontena atau aplikasi luaran.', + remoteConnHelper2: 'Gunakan alamat ini untuk persekitaran bukan kontena atau sambungan luar.', + remoteConnHelper3: + 'Alamat akses lalai ialah IP hos. Untuk mengubahnya, pergi ke item konfigurasi "Alamat Akses Lalai" pada halaman tetapan panel.', localIP: 'IP Tempatan', }, aiTools: { @@ -1889,6 +1890,7 @@ const message = { forceUnbind: 'Paksakan Nyahikat', forceUnbindHelper: 'Memaksa nyahikat akan mengabaikan sebarang ralat yang berlaku semasa proses nyahikat dan akhirnya melepaskan ikatan lesen.', + updateForce: 'Kemas kini paksa (abaikan semua ralat semasa nyahikatan untuk memastikan operasi akhir berjaya)', trialInfo: 'Versi', authorizationId: 'ID Kebenaran Langganan', authorizedUser: 'Pengguna yang Dibenarkan', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index b797b5e4e..02a4d2d57 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -599,8 +599,9 @@ const message = { containerConnHelper: 'Este endereço de conexão pode ser utilizado por aplicações que estão em execução nos ambientes do site (PHP, etc.) ou no contêiner.', remoteConn: 'Conexão externa', - remoteConnHelper2: - 'Este endereço de conexão pode ser utilizado por aplicações que estão fora do contêiner ou por aplicações externas.', + remoteConnHelper2: 'Use este endereço para ambientes não-container ou conexões externas.', + remoteConnHelper3: + 'O endereço de acesso padrão é o IP do host. Para modificá-lo, acesse o item de configuração "Endereço de Acesso Padrão" na página de configurações do painel.', localIP: 'IP local', }, aiTools: { @@ -1876,6 +1877,8 @@ const message = { forceUnbind: 'Forçar Desvinculação', forceUnbindHelper: 'Forçar a desvinculação ignorará quaisquer erros que ocorram durante o processo de desvinculação e, em última análise, liberará a vinculação da licença.', + updateForce: + 'Atualização forçada (ignora todos os erros durante o desvinculamento para garantir o sucesso da operação final)', trialInfo: 'Versão', authorizationId: 'ID de autorização', authorizedUser: 'Usuário autorizado', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 56615fd3a..271c155fa 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -597,8 +597,9 @@ const message = { containerConnHelper: 'Этот адрес подключения может использоваться приложениями, работающими в среде выполнения веб-сайта (PHP и т.д.) или контейнере.', remoteConn: 'Внешнее подключение', - remoteConnHelper2: - 'Этот адрес подключения может использоваться приложениями, работающими вне контейнера или внешними приложениями.', + remoteConnHelper2: 'Используйте этот адрес для неконтейнерных сред или внешних подключений.', + remoteConnHelper3: + 'Адрес доступа по умолчанию - это IP хоста. Для изменения перейдите к пункту конфигурации "Адрес доступа по умолчанию" на странице настроек панели.', localIP: 'Локальный IP', }, aiTools: { @@ -1875,6 +1876,8 @@ const message = { forceUnbind: 'Принудительное отвязывание', forceUnbindHelper: 'Принудительное отвязывание будет игнорировать любые ошибки, возникающие в процессе отвязывания, и в конечном итоге освободит привязку лицензии.', + updateForce: + 'Принудительное обновление (игнорировать все ошибки при отвязке для гарантии успешного завершения операции)', trialInfo: 'Версия', authorizationId: 'ID авторизации подписки', authorizedUser: 'Авторизованный пользователь', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 53ba0f6bf..c9bd2fa0b 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -583,7 +583,8 @@ const message = { connAddress: '地址', containerConnHelper: 'PHP 執行環境/容器安裝的應用程式使用此連接地址', remoteConn: '外部連接', - remoteConnHelper2: '非容器或外部連接使用此地址', + remoteConnHelper2: '非容器環境或外部連接需使用此地址。', + remoteConnHelper3: '預設存取地址為主機IP,修改請前往面板設定頁面的「預設存取地址」配置項。', localIP: '本機 IP', }, aiTools: { @@ -1785,6 +1786,7 @@ const message = { versionConstraint: '{0} 版本買斷', forceUnbind: '強制解除綁定', forceUnbindHelper: '強制解除綁定將忽略解除過程中產生的錯誤,最終解除許可證綁定。', + updateForce: '強制更新(忽略解除綁定過程中的所有錯誤,確保最終操作成功)', trialInfo: '版本', authorizationId: '訂閱授權 ID', authorizedUser: '被授權方', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index d9340b2af..0fe56d0a2 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -581,7 +581,8 @@ const message = { connAddress: '地址', containerConnHelper: 'PHP 运行环境/容器安装的应用使用此连接地址', remoteConn: '外部连接', - remoteConnHelper2: '非容器或外部连接使用此地址', + remoteConnHelper2: '非容器环境或外部连接需使用此地址。', + remoteConnHelper3: '默认访问地址为主机IP,修改请前往面板设置页面的「默认访问地址」配置项。', localIP: '本机 IP', }, aiTools: { @@ -1778,6 +1779,7 @@ const message = { versionConstraint: '{0} 版本买断', forceUnbind: '强制解绑', forceUnbindHelper: '强制解绑,会忽略解绑过程中产生的错误并最终解除许可证绑定', + updateForce: '强制更新(忽略解绑过程中的所有错误,确保最终操作成功)', trialInfo: '版本', authorizationId: '订阅授权 ID', authorizedUser: '被授权方', diff --git a/frontend/src/layout/components/Sidebar/components/Collapse.vue b/frontend/src/layout/components/Sidebar/components/Collapse.vue index b37088611..9d0f1694e 100644 --- a/frontend/src/layout/components/Sidebar/components/Collapse.vue +++ b/frontend/src/layout/components/Sidebar/components/Collapse.vue @@ -165,6 +165,7 @@ const changeNode = (command: string) => { } if (command == 'local') { globalStore.currentNode = command || 'local'; + globalStore.currentNodeAddr = ''; globalStore.isOffline = false; router.push({ name: 'home' }).then(() => { window.location.reload(); @@ -186,6 +187,7 @@ const changeNode = (command: string) => { return; } globalStore.currentNode = command || 'local'; + globalStore.currentNodeAddr = item.addr; globalStore.isOffline = item.isOffline; router.push({ name: 'home' }).then(() => { window.location.reload(); diff --git a/frontend/src/store/interface/index.ts b/frontend/src/store/interface/index.ts index b6d75f860..21cc906fd 100644 --- a/frontend/src/store/interface/index.ts +++ b/frontend/src/store/interface/index.ts @@ -44,6 +44,7 @@ export interface GlobalState { errStatus: string; currentNode: string; + currentNodeAddr: string; isOffline: boolean; } diff --git a/frontend/src/store/modules/global.ts b/frontend/src/store/modules/global.ts index b5d4705df..45d7e39f0 100644 --- a/frontend/src/store/modules/global.ts +++ b/frontend/src/store/modules/global.ts @@ -47,6 +47,7 @@ const GlobalStore = defineStore({ errStatus: '', currentNode: 'local', + currentNodeAddr: '', isOffline: false, }), getters: { diff --git a/frontend/src/views/container/container/index.vue b/frontend/src/views/container/container/index.vue index c08a3394c..4221a0ebb 100644 --- a/frontend/src/views/container/container/index.vue +++ b/frontend/src/views/container/container/index.vue @@ -3,7 +3,7 @@ -