From 4ca25d51d7981b3a0b39add6a4fac25796da9a64 Mon Sep 17 00:00:00 2001 From: zhengkunwang <31820853+zhengkunwang223@users.noreply.github.com> Date: Tue, 26 Sep 2023 22:50:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Node.js=20=E7=8E=AF=E5=A2=83=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=90=AF=E5=8A=A8=E3=80=81=E5=81=9C=E6=AD=A2=E3=80=81?= =?UTF-8?q?=E9=87=8D=E5=90=AF=E6=93=8D=E4=BD=9C=20(#2394)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/app.go | 4 +- backend/app/api/v1/runtime.go | 23 ++ backend/app/dto/request/app.go | 1 + backend/app/dto/request/runtime.go | 5 + backend/app/service/app.go | 9 +- backend/app/service/runtime.go | 40 +++ backend/app/service/runtime_utils.go | 108 ++++-- backend/constant/runtime.go | 7 + backend/i18n/lang/en.yaml | 1 + backend/i18n/lang/zh-Hant.yaml | 1 + backend/i18n/lang/zh.yaml | 1 + backend/router/ro_runtime.go | 2 + backend/utils/docker/docker.go | 4 + cmd/server/docs/docs.go | 56 +++ cmd/server/docs/swagger.json | 56 +++ cmd/server/docs/swagger.yaml | 36 ++ frontend/src/api/interface/runtime.ts | 5 + frontend/src/api/modules/runtime.ts | 4 + frontend/src/components/status/index.vue | 11 +- frontend/src/lang/modules/en.ts | 10 + frontend/src/lang/modules/tw.ts | 8 + frontend/src/lang/modules/zh.ts | 8 + frontend/src/views/app-store/apps/index.vue | 3 +- frontend/src/views/app-store/detail/index.vue | 21 +- .../website/runtime/node/create/index.vue | 337 ------------------ .../src/views/website/runtime/node/index.vue | 66 +++- .../website/runtime/node/operate/index.vue | 1 + 27 files changed, 440 insertions(+), 388 deletions(-) delete mode 100644 frontend/src/views/website/runtime/node/create/index.vue diff --git a/backend/app/api/v1/app.go b/backend/app/api/v1/app.go index f24c2f456..f946218c3 100644 --- a/backend/app/api/v1/app.go +++ b/backend/app/api/v1/app.go @@ -93,14 +93,14 @@ func (b *BaseApi) GetApp(c *gin.Context) { // @Security ApiKeyAuth // @Router /apps/detail/:appId/:version/:type [get] func (b *BaseApi) GetAppDetail(c *gin.Context) { - appId, err := helper.GetIntParamByKey(c, "appId") + appID, err := helper.GetIntParamByKey(c, "appId") if err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil) return } version := c.Param("version") appType := c.Param("type") - appDetailDTO, err := appService.GetAppDetail(appId, version, appType) + appDetailDTO, err := appService.GetAppDetail(appID, version, appType) if err != nil { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return diff --git a/backend/app/api/v1/runtime.go b/backend/app/api/v1/runtime.go index b529d48a1..841b84391 100644 --- a/backend/app/api/v1/runtime.go +++ b/backend/app/api/v1/runtime.go @@ -143,3 +143,26 @@ func (b *BaseApi) GetNodePackageRunScript(c *gin.Context) { } helper.SuccessWithData(c, res) } + +// @Tags Runtime +// @Summary Operate runtime +// @Description 操作运行环境 +// @Accept json +// @Param request body request.RuntimeOperate true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /runtimes/operate [post] +// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"操作运行环境 [name]","formatEN":"Operate runtime [name]"} +func (b *BaseApi) OperateRuntime(c *gin.Context) { + var req request.RuntimeOperate + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + err := runtimeService.OperateRuntime(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithOutData(c) +} diff --git a/backend/app/dto/request/app.go b/backend/app/dto/request/app.go index 0abe9b6c5..08a88bec8 100644 --- a/backend/app/dto/request/app.go +++ b/backend/app/dto/request/app.go @@ -11,6 +11,7 @@ type AppSearch struct { Tags []string `json:"tags"` Type string `json:"type"` Recommend bool `json:"recommend"` + Resource string `json:"resource"` } type AppInstallCreate struct { diff --git a/backend/app/dto/request/runtime.go b/backend/app/dto/request/runtime.go index 503e02d5a..eb26c3706 100644 --- a/backend/app/dto/request/runtime.go +++ b/backend/app/dto/request/runtime.go @@ -47,3 +47,8 @@ type RuntimeUpdate struct { type NodePackageReq struct { CodeDir string `json:"codeDir"` } + +type RuntimeOperate struct { + Operate string `json:"operate"` + ID uint `json:"ID"` +} diff --git a/backend/app/service/app.go b/backend/app/service/app.go index fb8ee14b4..506373668 100644 --- a/backend/app/service/app.go +++ b/backend/app/service/app.go @@ -61,6 +61,9 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) { if req.Recommend { opts = append(opts, appRepo.GetRecommend()) } + if req.Resource != "" { + opts = append(opts, appRepo.WithResource(req.Resource)) + } if len(req.Tags) != 0 { tags, err := tagRepo.GetByKeys(req.Tags) if err != nil { @@ -151,12 +154,12 @@ func (a AppService) GetApp(key string) (*response.AppDTO, error) { return &appDTO, nil } -func (a AppService) GetAppDetail(appId uint, version, appType string) (response.AppDetailDTO, error) { +func (a AppService) GetAppDetail(appID uint, version, appType string) (response.AppDetailDTO, error) { var ( appDetailDTO response.AppDetailDTO opts []repo.DBOption ) - opts = append(opts, appDetailRepo.WithAppId(appId), appDetailRepo.WithVersion(version)) + opts = append(opts, appDetailRepo.WithAppId(appID), appDetailRepo.WithVersion(version)) detail, err := appDetailRepo.GetFirst(opts...) if err != nil { return appDetailDTO, err @@ -165,7 +168,7 @@ func (a AppService) GetAppDetail(appId uint, version, appType string) (response. appDetailDTO.Enable = true if appType == "runtime" { - app, err := appRepo.GetFirst(commonRepo.WithByID(appId)) + app, err := appRepo.GetFirst(commonRepo.WithByID(appID)) if err != nil { return appDetailDTO, err } diff --git a/backend/app/service/runtime.go b/backend/app/service/runtime.go index b9e2b50fd..163337290 100644 --- a/backend/app/service/runtime.go +++ b/backend/app/service/runtime.go @@ -31,6 +31,7 @@ type IRuntimeService interface { Update(req request.RuntimeUpdate) error Get(id uint) (res *response.RuntimeDTO, err error) GetNodePackageRunScript(req request.NodePackageReq) ([]response.PackageScripts, error) + OperateRuntime(req request.RuntimeOperate) error } func NewRuntimeService() IRuntimeService { @@ -357,3 +358,42 @@ func (r *RuntimeService) GetNodePackageRunScript(req request.NodePackageReq) ([] } return packageScripts, nil } + +func (r *RuntimeService) OperateRuntime(req request.RuntimeOperate) error { + runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID)) + if err != nil { + return err + } + defer func() { + if err != nil { + runtime.Status = constant.RuntimeError + runtime.Message = err.Error() + _ = runtimeRepo.Save(runtime) + } + }() + switch req.Operate { + case constant.RuntimeUp: + if err = runComposeCmdWithLog(req.Operate, runtime.GetComposePath(), runtime.GetLogPath()); err != nil { + return err + } + if err = SyncRuntimeContainerStatus(runtime); err != nil { + return err + } + case constant.RuntimeDown: + if err = runComposeCmdWithLog(req.Operate, runtime.GetComposePath(), runtime.GetLogPath()); err != nil { + return err + } + runtime.Status = constant.RuntimeStopped + case constant.RuntimeRestart: + if err = runComposeCmdWithLog(constant.RuntimeDown, runtime.GetComposePath(), runtime.GetLogPath()); err != nil { + return err + } + if err = runComposeCmdWithLog(constant.RuntimeUp, runtime.GetComposePath(), runtime.GetLogPath()); err != nil { + return err + } + if err = SyncRuntimeContainerStatus(runtime); err != nil { + return err + } + } + return runtimeRepo.Save(runtime) +} diff --git a/backend/app/service/runtime_utils.go b/backend/app/service/runtime_utils.go index 045ad618d..69f0c8a33 100644 --- a/backend/app/service/runtime_utils.go +++ b/backend/app/service/runtime_utils.go @@ -42,7 +42,7 @@ func handleNode(create request.RuntimeCreate, runtime *model.Runtime, fileOp fil } runtime.DockerCompose = string(composeContent) runtime.Env = string(envContent) - runtime.Status = constant.RuntimeStarting + runtime.Status = constant.RuntimeCreating runtime.CodeDir = create.CodeDir go startRuntime(runtime) @@ -88,29 +88,39 @@ func handlePHP(create request.RuntimeCreate, runtime *model.Runtime, fileOp file } func startRuntime(runtime *model.Runtime) { - cmd := exec.Command("docker-compose", "-f", runtime.GetComposePath(), "up", "-d") - logPath := runtime.GetLogPath() - logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) - if err != nil { - global.LOG.Errorf("Failed to open log file: %v", err) + if err := runComposeCmdWithLog("up", runtime.GetComposePath(), runtime.GetLogPath()); err != nil { + runtime.Status = constant.RuntimeError + runtime.Message = err.Error() + _ = runtimeRepo.Save(runtime) return } - multiWriterStdout := io.MultiWriter(os.Stdout, logFile) - cmd.Stdout = multiWriterStdout - var stderrBuf bytes.Buffer - multiWriterStderr := io.MultiWriter(&stderrBuf, logFile, os.Stderr) - cmd.Stderr = multiWriterStderr - err = cmd.Run() - if err != nil { + if err := SyncRuntimeContainerStatus(runtime); err != nil { runtime.Status = constant.RuntimeError - runtime.Message = buserr.New(constant.ErrRuntimeStart).Error() + ":" + stderrBuf.String() - } else { - runtime.Status = constant.RuntimeRunning - runtime.Message = "" + runtime.Message = err.Error() + _ = runtimeRepo.Save(runtime) + return } +} - _ = runtimeRepo.Save(runtime) +func reCreateRuntime(runtime *model.Runtime) { + var err error + defer func() { + if err != nil { + runtime.Status = constant.RuntimeError + runtime.Message = err.Error() + _ = runtimeRepo.Save(runtime) + } + }() + if err = runComposeCmdWithLog("down", runtime.GetComposePath(), runtime.GetLogPath()); err != nil { + return + } + if err = runComposeCmdWithLog("up", runtime.GetComposePath(), runtime.GetLogPath()); err != nil { + return + } + if err := SyncRuntimeContainerStatus(runtime); err != nil { + return + } } func runComposeCmdWithLog(operate string, composePath string, logPath string) error { @@ -136,23 +146,57 @@ func runComposeCmdWithLog(operate string, composePath string, logPath string) er return nil } -func reCreateRuntime(runtime *model.Runtime) { - var err error - defer func() { +func SyncRuntimeContainerStatus(runtime *model.Runtime) error { + env, err := gotenv.Unmarshal(runtime.Env) + if err != nil { + return err + } + var containerNames []string + if containerName, ok := env["CONTAINER_NAME"]; !ok { + return buserr.New("ErrContainerNameNotFound") + } else { + containerNames = append(containerNames, containerName) + } + cli, err := docker.NewClient() + if err != nil { + return err + } + containers, err := cli.ListContainersByName(containerNames) + if err != nil { + return err + } + if len(containers) == 0 { + return buserr.WithNameAndErr("ErrContainerNotFound", containerNames[0], nil) + } + container := containers[0] + + interval := 10 * time.Second + retries := 60 + for i := 0; i < retries; i++ { + resp, err := cli.InspectContainer(container.ID) if err != nil { - runtime.Status = constant.RuntimeError - runtime.Message = err.Error() - _ = runtimeRepo.Save(runtime) + time.Sleep(interval) + continue } - }() - if err = runComposeCmdWithLog("down", runtime.GetComposePath(), runtime.GetLogPath()); err != nil { - return + if resp.State.Health != nil { + status := strings.ToLower(resp.State.Health.Status) + switch status { + case "starting": + runtime.Status = constant.RuntimeStarting + _ = runtimeRepo.Save(runtime) + case "healthy": + runtime.Status = constant.RuntimeRunning + _ = runtimeRepo.Save(runtime) + return nil + case "unhealthy": + runtime.Status = constant.RuntimeUnhealthy + _ = runtimeRepo.Save(runtime) + return nil + } + } + time.Sleep(interval) } - if err = runComposeCmdWithLog("up", runtime.GetComposePath(), runtime.GetLogPath()); err != nil { - return - } - runtime.Status = constant.RuntimeRunning - _ = runtimeRepo.Save(runtime) + return nil } func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) { diff --git a/backend/constant/runtime.go b/backend/constant/runtime.go index 177baee71..7381d79e5 100644 --- a/backend/constant/runtime.go +++ b/backend/constant/runtime.go @@ -10,10 +10,17 @@ const ( RuntimeStarting = "starting" RuntimeRunning = "running" RuntimeReCreating = "recreating" + RuntimeStopped = "stopped" + RuntimeUnhealthy = "unhealthy" + RuntimeCreating = "creating" RuntimePHP = "php" RuntimeNode = "node" RuntimeProxyUnix = "unix" RuntimeProxyTcp = "tcp" + + RuntimeUp = "up" + RuntimeDown = "down" + RuntimeRestart = "restart" ) diff --git a/backend/i18n/lang/en.yaml b/backend/i18n/lang/en.yaml index 4c5ef4127..123aeb127 100644 --- a/backend/i18n/lang/en.yaml +++ b/backend/i18n/lang/en.yaml @@ -102,6 +102,7 @@ ErrDelWithWebsite: "The operating environment has been associated with a website ErrRuntimeStart: "Failed to start" ErrPackageJsonNotFound: "package.json file does not exist" ErrScriptsNotFound: "No scripts configuration item was found in package.json" +ErrContainerNameNotFound: "Unable to get container name, please check .env file" #setting ErrBackupInUsed: "The backup account is already being used in a cronjob and cannot be deleted." diff --git a/backend/i18n/lang/zh-Hant.yaml b/backend/i18n/lang/zh-Hant.yaml index bd9821cca..e2bb4e071 100644 --- a/backend/i18n/lang/zh-Hant.yaml +++ b/backend/i18n/lang/zh-Hant.yaml @@ -102,6 +102,7 @@ ErrDelWithWebsite: "運行環境已經關聯網站,無法刪除" ErrRuntimeStart: "啟動失敗" ErrPackageJsonNotFound: "package.json 文件不存在" ErrScriptsNotFound: "沒有在 package.json 中找到 scripts 配置項" +ErrContainerNameNotFound: "無法取得容器名稱,請檢查 .env 文件" #setting ErrBackupInUsed: "該備份帳號已在計劃任務中使用,無法刪除" diff --git a/backend/i18n/lang/zh.yaml b/backend/i18n/lang/zh.yaml index d1d6000fc..95420123d 100644 --- a/backend/i18n/lang/zh.yaml +++ b/backend/i18n/lang/zh.yaml @@ -102,6 +102,7 @@ ErrDelWithWebsite: "运行环境已经关联网站,无法删除" ErrRuntimeStart: "启动失败" ErrPackageJsonNotFound: "package.json 文件不存在" ErrScriptsNotFound: "没有在 package.json 中找到 scripts 配置项" +ErrContainerNameNotFound: "无法获取容器名称,请检查 .env 文件" #setting ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除" diff --git a/backend/router/ro_runtime.go b/backend/router/ro_runtime.go index 148d380d2..d3a331480 100644 --- a/backend/router/ro_runtime.go +++ b/backend/router/ro_runtime.go @@ -21,5 +21,7 @@ func (r *RuntimeRouter) InitRuntimeRouter(Router *gin.RouterGroup) { groupRouter.POST("/update", baseApi.UpdateRuntime) groupRouter.GET("/:id", baseApi.GetRuntime) groupRouter.POST("/node/package", baseApi.GetNodePackageRunScript) + groupRouter.POST("/operate", baseApi.OperateRuntime) } + } diff --git a/backend/utils/docker/docker.go b/backend/utils/docker/docker.go index a2dfad9b9..2bf73230c 100644 --- a/backend/utils/docker/docker.go +++ b/backend/utils/docker/docker.go @@ -80,6 +80,10 @@ func (c Client) DeleteImage(imageID string) error { return nil } +func (c Client) InspectContainer(containerID string) (types.ContainerJSON, error) { + return c.cli.ContainerInspect(context.Background(), containerID) +} + func (c Client) PullImage(imageName string, force bool) error { if !force { exist, err := c.CheckImageExist(imageName) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 8879e48bd..0080d6ab9 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -7863,6 +7863,48 @@ const docTemplate = `{ } } }, + "/runtimes/operate": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "操作运行环境", + "consumes": [ + "application/json" + ], + "tags": [ + "Runtime" + ], + "summary": "Operate runtime", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.RuntimeOperate" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "id" + ], + "formatEN": "Operate runtime [name]", + "formatZH": "操作运行环境 [name]", + "paramKeys": [] + } + } + }, "/runtimes/search": { "post": { "security": [ @@ -15732,6 +15774,9 @@ const docTemplate = `{ "recommend": { "type": "boolean" }, + "resource": { + "type": "string" + }, "tags": { "type": "array", "items": { @@ -16491,6 +16536,17 @@ const docTemplate = `{ } } }, + "request.RuntimeOperate": { + "type": "object", + "properties": { + "ID": { + "type": "integer" + }, + "operate": { + "type": "string" + } + } + }, "request.RuntimeSearch": { "type": "object", "required": [ diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 12ac5cf97..acd73c547 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -7856,6 +7856,48 @@ } } }, + "/runtimes/operate": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "操作运行环境", + "consumes": [ + "application/json" + ], + "tags": [ + "Runtime" + ], + "summary": "Operate runtime", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.RuntimeOperate" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "id" + ], + "formatEN": "Operate runtime [name]", + "formatZH": "操作运行环境 [name]", + "paramKeys": [] + } + } + }, "/runtimes/search": { "post": { "security": [ @@ -15725,6 +15767,9 @@ "recommend": { "type": "boolean" }, + "resource": { + "type": "string" + }, "tags": { "type": "array", "items": { @@ -16484,6 +16529,17 @@ } } }, + "request.RuntimeOperate": { + "type": "object", + "properties": { + "ID": { + "type": "integer" + }, + "operate": { + "type": "string" + } + } + }, "request.RuntimeSearch": { "type": "object", "required": [ diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 6f60ff723..c9429e25d 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -2639,6 +2639,8 @@ definitions: type: integer recommend: type: boolean + resource: + type: string tags: items: type: string @@ -3151,6 +3153,13 @@ definitions: id: type: integer type: object + request.RuntimeOperate: + properties: + ID: + type: integer + operate: + type: string + type: object request.RuntimeSearch: properties: name: @@ -9086,6 +9095,33 @@ paths: summary: Get Node package scripts tags: - Runtime + /runtimes/operate: + post: + consumes: + - application/json + description: 操作运行环境 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/request.RuntimeOperate' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Operate runtime + tags: + - Runtime + x-panel-log: + BeforeFuntions: [] + bodyKeys: + - id + formatEN: Operate runtime [name] + formatZH: 操作运行环境 [name] + paramKeys: [] /runtimes/search: post: consumes: diff --git a/frontend/src/api/interface/runtime.ts b/frontend/src/api/interface/runtime.ts index aa88a226d..82075a8d1 100644 --- a/frontend/src/api/interface/runtime.ts +++ b/frontend/src/api/interface/runtime.ts @@ -68,4 +68,9 @@ export namespace Runtime { id: number; forceDelete: boolean; } + + export interface RuntimeOperate { + ID: number; + operate: string; + } } diff --git a/frontend/src/api/modules/runtime.ts b/frontend/src/api/modules/runtime.ts index b4c60c24d..02c26a191 100644 --- a/frontend/src/api/modules/runtime.ts +++ b/frontend/src/api/modules/runtime.ts @@ -25,3 +25,7 @@ export const UpdateRuntime = (req: Runtime.RuntimeUpdate) => { export const GetNodeScripts = (req: Runtime.NodeReq) => { return http.post(`/runtimes/node/package`, req); }; + +export const OperateRuntime = (req: Runtime.RuntimeOperate) => { + return http.post(`/runtimes/operate`, req); +}; diff --git a/frontend/src/components/status/index.vue b/frontend/src/components/status/index.vue index ab52b35ec..631bcde62 100644 --- a/frontend/src/components/status/index.vue +++ b/frontend/src/components/status/index.vue @@ -34,7 +34,16 @@ const getType = (status: string) => { } }; -const loadingStatus = ['installing', 'building', 'restarting', 'upgrading', 'rebuilding', 'recreating', 'creating']; +const loadingStatus = [ + 'installing', + 'building', + 'restarting', + 'upgrading', + 'rebuilding', + 'recreating', + 'creating', + 'starting', +]; const loadingIcon = (status: string): boolean => { return loadingStatus.indexOf(status) > -1; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index c7bffe060..d9ae5240f 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -230,6 +230,7 @@ const message = { unUsed: 'Unused', starting: 'Starting', recreating: 'Recreating', + creating: 'Creating', }, units: { second: 'Second', @@ -242,6 +243,11 @@ const message = { time: 'Time', core: 'Core', }, + operate: { + down: 'Stop', + up: 'Start', + restart: 'Restart', + }, }, menu: { home: 'Overview', @@ -1703,6 +1709,10 @@ const message = { runScriptHelper: 'The startup command list is parsed from the package.json file in the source directory', open: 'Open', close: 'Close', + operatorHelper: + 'The {0} operation will be performed on the selected operating environment. Do you want to continue? ', + statusHelper: + 'Status description: Starting - the container has been started, but the application is starting; abnormal - the container has been started, but the application status is abnormal', }, process: { pid: 'Process ID', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index ba434c641..15964fec8 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -228,6 +228,7 @@ const message = { unUsed: '未使用', starting: '啟動中', recreating: '重建中', + creating: '創建中', }, units: { second: '秒', @@ -240,6 +241,11 @@ const message = { time: '次', core: '核', }, + operate: { + down: '停止', + up: '启动', + restart: '重启', + }, }, menu: { home: '概覽', @@ -1612,6 +1618,8 @@ const message = { runScriptHelper: '啟動命令是指容器啟動後運行的命令', open: '開啟', close: '關閉', + operatorHelper: '將對選取的執行環境進行 {0} 操作,是否繼續? ', + statusHelper: '狀態說明:啟動中-容器已啟動,但應用正在啟動;異常-容器已啟動,但應用狀態異常', }, process: { pid: '進程ID', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index d06d2a516..e2e06132e 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -228,6 +228,7 @@ const message = { unUsed: '未使用', starting: '启动中', recreating: '重建中', + creating: '创建中', }, units: { second: '秒', @@ -240,6 +241,11 @@ const message = { time: '次', core: '核', }, + operate: { + down: '停止', + up: '启动', + restart: '重启', + }, }, menu: { home: '概览', @@ -1612,6 +1618,8 @@ const message = { runScriptHelper: '启动命令列表是从源码目录下的 package.json 文件中解析而来', open: '放开', close: '关闭', + operatorHelper: '将对选中的运行环境进行 {0} 操作,是否继续?', + statusHelper: '状态说明:启动中-容器已启动,但应用正在启动;异常-容器已启动,但应用状态异常', }, process: { pid: '进程ID', diff --git a/frontend/src/views/app-store/apps/index.vue b/frontend/src/views/app-store/apps/index.vue index 9d3acadde..1e099a794 100644 --- a/frontend/src/views/app-store/apps/index.vue +++ b/frontend/src/views/app-store/apps/index.vue @@ -130,7 +130,7 @@ - + @@ -174,7 +174,6 @@ const colorArr = ['#005eeb', '#008B45', '#BEBEBE', '#FFF68F', '#FFFF00', '#8B000 const loading = ref(false); const activeTag = ref('all'); const showDetail = ref(false); -const appId = ref(0); const canUpdate = ref(false); const syncing = ref(false); const detailRef = ref(); diff --git a/frontend/src/views/app-store/detail/index.vue b/frontend/src/views/app-store/detail/index.vue index a4c834bd5..15919c7d0 100644 --- a/frontend/src/views/app-store/detail/index.vue +++ b/frontend/src/views/app-store/detail/index.vue @@ -131,14 +131,19 @@ const toLink = (link: string) => { }; const openInstall = () => { - if (app.value.type === 'php') { - router.push({ path: '/websites/runtime/php' }); - } else { - const params = { - app: app.value, - }; - installRef.value.acceptParams(params); - open.value = false; + switch (app.value.type) { + case 'php': + router.push({ path: '/websites/runtimes/php' }); + break; + case 'node': + router.push({ path: '/websites/runtimes/node' }); + break; + default: + const params = { + app: app.value, + }; + installRef.value.acceptParams(params); + open.value = false; } }; diff --git a/frontend/src/views/website/runtime/node/create/index.vue b/frontend/src/views/website/runtime/node/create/index.vue deleted file mode 100644 index d1efc08cb..000000000 --- a/frontend/src/views/website/runtime/node/create/index.vue +++ /dev/null @@ -1,337 +0,0 @@ - - - diff --git a/frontend/src/views/website/runtime/node/index.vue b/frontend/src/views/website/runtime/node/index.vue index 500e1627d..3ccccb69d 100644 --- a/frontend/src/views/website/runtime/node/index.vue +++ b/frontend/src/views/website/runtime/node/index.vue @@ -2,6 +2,13 @@
+