diff --git a/agent/app/api/v2/dashboard.go b/agent/app/api/v2/dashboard.go index b9fb3e644..92c31581d 100644 --- a/agent/app/api/v2/dashboard.go +++ b/agent/app/api/v2/dashboard.go @@ -137,3 +137,24 @@ func (b *BaseApi) LoadDashboardCurrentInfo(c *gin.Context) { data := dashboardService.LoadCurrentInfo(ioOption, netOption) helper.SuccessWithData(c, data) } + +// @Tags Dashboard +// @Summary System restart +// @Accept json +// @Param operation path string true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /dashboard/system/restart/:operation [post] +func (b *BaseApi) SystemRestart(c *gin.Context) { + operation, ok := c.Params.Get("operation") + if !ok { + helper.BadRequest(c, errors.New("error operation in path")) + return + } + if err := dashboardService.Restart(operation); err != nil { + helper.InternalServer(c, err) + return + } + helper.SuccessWithOutData(c) +} diff --git a/agent/app/service/ai.go b/agent/app/service/ai.go index c8962ce35..de7d22b8f 100644 --- a/agent/app/service/ai.go +++ b/agent/app/service/ai.go @@ -118,7 +118,9 @@ func (u *AIToolService) Create(req dto.OllamaModelName) error { } return nil }, nil) - _ = taskItem.Execute() + if err := taskItem.Execute(); err != nil { + _ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) + } }() return nil } diff --git a/agent/app/service/dashboard.go b/agent/app/service/dashboard.go index 64278d8bf..744ae7cec 100644 --- a/agent/app/service/dashboard.go +++ b/agent/app/service/dashboard.go @@ -2,6 +2,7 @@ package service import ( "encoding/json" + "fmt" network "net" "os" "sort" @@ -38,6 +39,7 @@ type IDashboardService interface { LoadAppLauncher() ([]dto.AppLauncher, error) ListLauncherOption(filter string) ([]dto.LauncherOption, error) + Restart(operation string) error } func NewIDashboardService() IDashboardService { @@ -52,6 +54,26 @@ func (u *DashboardService) Sync(req []dto.AppLauncherSync) error { return launcherRepo.SyncAll(launchers) } +func (u *DashboardService) Restart(operation string) error { + if operation != "1panel" && operation != "system" && operation != "1panel-agent" { + return fmt.Errorf("handle restart operation %s failed, err: nonsupport such operation", operation) + } + itemCmd := fmt.Sprintf("%s systemctl restart 1panel-agent.service && %s systemctl restart 1panel-core.service", cmd.SudoHandleCmd(), cmd.SudoHandleCmd()) + if operation == "system" { + itemCmd = fmt.Sprintf("%s reboot", cmd.SudoHandleCmd()) + } + if operation == "1panel-agent" { + itemCmd = fmt.Sprintf("%s systemctl restart 1panel-agent.service", cmd.SudoHandleCmd()) + } + go func() { + stdout, err := cmd.Exec(itemCmd) + if err != nil { + global.LOG.Errorf("handle %s failed, err: %v", itemCmd, stdout) + } + }() + return nil +} + func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) { var baseInfo dto.OsInfo hostInfo, err := host.Info() diff --git a/agent/router/ro_dashboard.go b/agent/router/ro_dashboard.go index da5e2677d..828a32a6e 100644 --- a/agent/router/ro_dashboard.go +++ b/agent/router/ro_dashboard.go @@ -18,5 +18,6 @@ func (s *DashboardRouter) InitRouter(Router *gin.RouterGroup) { cmdRouter.GET("/base/:ioOption/:netOption", baseApi.LoadDashboardBaseInfo) cmdRouter.GET("/current/node", baseApi.LoadCurrentInfoForNode) cmdRouter.GET("/current/:ioOption/:netOption", baseApi.LoadDashboardCurrentInfo) + cmdRouter.POST("/system/restart/:operation", baseApi.SystemRestart) } } diff --git a/core/app/service/upgrade.go b/core/app/service/upgrade.go index a85e61de2..ffecf79c1 100644 --- a/core/app/service/upgrade.go +++ b/core/app/service/upgrade.go @@ -136,8 +136,13 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error { global.LOG.Info("backup original data successful, now start to upgrade!") - if err := files.CopyItem(false, true, path.Join(tmpDir, "1panel*"), "/usr/local/bin"); err != nil { - global.LOG.Errorf("upgrade 1panel failed, err: %v", err) + if err := files.CopyItem(false, true, path.Join(tmpDir, "1panel-core"), "/usr/local/bin"); err != nil { + global.LOG.Errorf("upgrade 1panel-core failed, err: %v", err) + u.handleRollback(originalDir, 1) + return + } + if err := files.CopyItem(false, true, path.Join(tmpDir, "1panel-agent"), "/usr/local/bin"); err != nil { + global.LOG.Errorf("upgrade 1panel-agent failed, err: %v", err) u.handleRollback(originalDir, 1) return } diff --git a/core/constant/common.go b/core/constant/common.go index 55998fe0c..2a5173514 100644 --- a/core/constant/common.go +++ b/core/constant/common.go @@ -51,16 +51,17 @@ var WebUrlMap = map[string]struct{}{ "/ai/model": {}, "/ai/gpu": {}, - "/containers": {}, - "/containers/container": {}, - "/containers/image": {}, - "/containers/network": {}, - "/containers/volume": {}, - "/containers/repo": {}, - "/containers/compose": {}, - "/containers/template": {}, - "/containers/setting": {}, - "/containers/dashboard": {}, + "/containers": {}, + "/containers/container/operate": {}, + "/containers/container": {}, + "/containers/image": {}, + "/containers/network": {}, + "/containers/volume": {}, + "/containers/repo": {}, + "/containers/compose": {}, + "/containers/template": {}, + "/containers/setting": {}, + "/containers/dashboard": {}, "/cronjobs": {}, "/cronjobs/cronjob": {}, @@ -148,7 +149,6 @@ var WebUrlMap = map[string]struct{}{ } var DynamicRoutes = []string{ - `^/containers/container/operate/[^?]+$`, `^/containers/composeDetail/[^/]+$`, `^/databases/mysql/setting/[^/]+/[^/]+$`, `^/databases/postgresql/setting/[^/]+/[^/]+$`, diff --git a/frontend/src/components/terminal/index.vue b/frontend/src/components/terminal/index.vue index 4a361bc46..7f190d446 100644 --- a/frontend/src/components/terminal/index.vue +++ b/frontend/src/components/terminal/index.vue @@ -77,19 +77,30 @@ const acceptParams = (props: WsProps) => { const newTerm = () => { const background = getComputedStyle(document.documentElement).getPropertyValue('--panel-terminal-bg-color').trim(); term.value = new Terminal({ - lineHeight: 1.2, - fontSize: 12, + lineHeight: terminalStore.lineHeight || 1.2, + fontSize: terminalStore.fontSize || 12, fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace", theme: { background: background, }, - cursorBlink: true, - cursorStyle: 'underline', - scrollback: 1000, - scrollSensitivity: 15, + cursorBlink: terminalStore.cursorBlink ? terminalStore.cursorBlink === 'Enable' : true, + cursorStyle: terminalStore.cursorStyle ? getStyle() : 'underline', + scrollback: terminalStore.scrollback || 1000, + scrollSensitivity: terminalStore.scrollSensitivity || 15, }); }; +const getStyle = (): 'underline' | 'block' | 'bar' => { + switch (terminalStore.cursorStyle) { + case 'bar': + return 'bar'; + case 'block': + return 'block'; + default: + return 'underline'; + } +}; + const init = (endpoint: string, args: string) => { if (initTerminal(true)) { initWebSocket(endpoint, args); diff --git a/frontend/src/layout/index.vue b/frontend/src/layout/index.vue index 0ede6924b..ae8693ddf 100644 --- a/frontend/src/layout/index.vue +++ b/frontend/src/layout/index.vue @@ -23,7 +23,7 @@ import { GlobalStore, MenuStore, TabsStore } from '@/store'; import { DeviceType } from '@/enums/app'; import { getSystemAvailable } from '@/api/modules/setting'; import { useRoute, useRouter } from 'vue-router'; -import { loadMasterProductProFromDB, loadProductProFromDB, getXpackSettingForTheme } from '@/utils/xpack'; +import { loadMasterProductProFromDB, loadProductProFromDB } from '@/utils/xpack'; import { useTheme } from '@/global/use-theme'; import TaskList from '@/components/task-list/index.vue'; const { switchTheme } = useTheme(); @@ -108,7 +108,6 @@ onMounted(() => { loadStatus(); loadProductProFromDB(); loadMasterProductProFromDB(); - getXpackSettingForTheme(); globalStore.isFullScreen = false; const mqList = window.matchMedia('(prefers-color-scheme: dark)'); diff --git a/frontend/src/utils/xpack.ts b/frontend/src/utils/xpack.ts index c80a76ad0..e6d2863b0 100644 --- a/frontend/src/utils/xpack.ts +++ b/frontend/src/utils/xpack.ts @@ -59,7 +59,7 @@ const loadDataFromDB = async () => { const res = await getSettingInfo(); document.title = res.data.panelName; globalStore.entrance = res.data.securityEntrance; - globalStore.setOpenMenuTabs(res.data.menuTabs === 'enable'); + globalStore.setOpenMenuTabs(res.data.menuTabs === 'Enable'); }; export async function loadProductProFromDB() { @@ -72,7 +72,6 @@ export async function loadProductProFromDB() { globalStore.productProExpires = Number(res.data.productPro); } } - loadDataFromDB(); } export async function loadMasterProductProFromDB() { @@ -84,6 +83,7 @@ export async function loadMasterProductProFromDB() { } switchTheme(); initFavicon(); + loadDataFromDB(); } export async function getXpackSettingForTheme() { diff --git a/frontend/src/views/setting/snapshot/index.vue b/frontend/src/views/setting/snapshot/index.vue index 03a2f712b..819732776 100644 --- a/frontend/src/views/setting/snapshot/index.vue +++ b/frontend/src/views/setting/snapshot/index.vue @@ -58,12 +58,12 @@ -
+
{{ $t('commons.button.expand') }}...
-
+
{{ $t('commons.button.collapse') }} diff --git a/frontend/src/views/toolbox/index.vue b/frontend/src/views/toolbox/index.vue index dc6352212..d583d5c4c 100644 --- a/frontend/src/views/toolbox/index.vue +++ b/frontend/src/views/toolbox/index.vue @@ -34,6 +34,9 @@ const confirmDialogRef = ref(); const globalStore = GlobalStore(); const onRestart = (type: string) => { + if (globalStore.currentNode != 'local' && type === '1panel') { + type = '1panel-agent'; + } restartType.value = type; let params = { header: i18n.global.t('home.restart_' + type),