mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 05:00:25 +08:00 
			
		
		
		
	当迁移了管理平台后,自动跳转到确认API配置页
This commit is contained in:
		@@ -2,6 +2,8 @@ package setup
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/configs"
 | 
			
		||||
	teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var isConfigured bool
 | 
			
		||||
@@ -16,3 +18,16 @@ func IsConfigured() bool {
 | 
			
		||||
	isConfigured = err == nil
 | 
			
		||||
	return isConfigured
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsNewInstalled IsNew 检查是否新安装
 | 
			
		||||
func IsNewInstalled() bool {
 | 
			
		||||
	homeDir, err := os.UserHomeDir()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	_, err = os.Stat(homeDir + "/." + teaconst.ProcessName + "/api.yaml")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,12 @@ func (this *IndexAction) RunGet(params struct {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//// 是否新安装
 | 
			
		||||
	if setup.IsNewInstalled() {
 | 
			
		||||
		this.RedirectURL("/setup/confirm")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 已登录跳转到dashboard
 | 
			
		||||
	if params.Auth.IsUser() {
 | 
			
		||||
		this.RedirectURL("/dashboard")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								internal/web/actions/default/setup/confirm/helper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								internal/web/actions/default/setup/confirm/helper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
package confirm
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/setup"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Helper struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
 | 
			
		||||
	if !setup.IsNewInstalled() {
 | 
			
		||||
		actionPtr.Object().RedirectURL("/")
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								internal/web/actions/default/setup/confirm/index.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								internal/web/actions/default/setup/confirm/index.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
			
		||||
 | 
			
		||||
package confirm
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/configs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/Tea"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"net/url"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IndexAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) RunGet(params struct{}) {
 | 
			
		||||
	var endpoints = []string{}
 | 
			
		||||
 | 
			
		||||
	config, err := configs.LoadAPIConfig()
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		endpoints = config.RPC.Endpoints
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Data["nodeId"] = config.NodeId
 | 
			
		||||
	this.Data["secret"] = config.Secret
 | 
			
		||||
 | 
			
		||||
	if len(endpoints) == 0 {
 | 
			
		||||
		endpoints = []string{""} // 初始化一个空的
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Data["endpoints"] = endpoints
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) RunPost(params struct {
 | 
			
		||||
	Endpoints []string
 | 
			
		||||
	NodeId    string
 | 
			
		||||
	Secret    string
 | 
			
		||||
 | 
			
		||||
	Must *actions.Must
 | 
			
		||||
}) {
 | 
			
		||||
	var endpoints = []string{}
 | 
			
		||||
	for _, endpoint := range params.Endpoints {
 | 
			
		||||
		if len(endpoint) > 0 {
 | 
			
		||||
			u, err := url.Parse(endpoint)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				this.Fail("API节点地址'" + endpoint + "'格式错误")
 | 
			
		||||
			}
 | 
			
		||||
			endpoint = u.Scheme + "://" + u.Host
 | 
			
		||||
			if u.Scheme != "http" && u.Scheme != "https" {
 | 
			
		||||
				this.Fail("API节点地址'" + endpoint + "'中的协议错误,目前只支持http或者https")
 | 
			
		||||
			}
 | 
			
		||||
			switch u.Scheme {
 | 
			
		||||
			case "http":
 | 
			
		||||
				if len(u.Port()) == 0 {
 | 
			
		||||
					endpoint += ":80"
 | 
			
		||||
				}
 | 
			
		||||
			case "https":
 | 
			
		||||
				if len(u.Port()) == 0 {
 | 
			
		||||
					endpoint += ":443"
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// 检测是否连接
 | 
			
		||||
			var config = &configs.APIConfig{}
 | 
			
		||||
			config.NodeId = params.NodeId
 | 
			
		||||
			config.Secret = params.Secret
 | 
			
		||||
			config.RPC.Endpoints = []string{endpoint}
 | 
			
		||||
			client, err := rpc.NewRPCClient(config, false)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				this.Fail("无法连接到API节点地址'" + endpoint + "':" + err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			_, err = client.APINodeRPC().FindCurrentAPINodeVersion(client.Context(0), &pb.FindCurrentAPINodeVersionRequest{})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				_ = client.Close()
 | 
			
		||||
				this.Fail("无法连接到API节点地址'" + endpoint + "':" + err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			_ = client.Close()
 | 
			
		||||
 | 
			
		||||
			endpoints = append(endpoints, endpoint)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(endpoints) == 0 {
 | 
			
		||||
		this.Fail("请输入至少一个API节点地址")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(params.NodeId) == 0 {
 | 
			
		||||
		this.Fail("请输入NodeId")
 | 
			
		||||
	}
 | 
			
		||||
	if len(params.Secret) == 0 {
 | 
			
		||||
		this.Fail("请输入Secret")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 创建配置文件
 | 
			
		||||
	config, err := configs.LoadAPIConfig()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		config = &configs.APIConfig{}
 | 
			
		||||
	}
 | 
			
		||||
	config.NodeId = params.NodeId
 | 
			
		||||
	config.Secret = params.Secret
 | 
			
		||||
	config.RPC.Endpoints = endpoints
 | 
			
		||||
	err = config.WriteFile(Tea.ConfigFile("api.yaml"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.Fail("配置保存失败:" + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rpcClient, err := rpc.SharedRPC()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.Fail("RPC配置无法读取:" + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	err = rpcClient.UpdateConfig(config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.Fail("重载RPC配置失败:" + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								internal/web/actions/default/setup/confirm/init.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								internal/web/actions/default/setup/confirm/init.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
package confirm
 | 
			
		||||
 | 
			
		||||
import "github.com/iwind/TeaGo"
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	TeaGo.BeforeStart(func(server *TeaGo.Server) {
 | 
			
		||||
		server.
 | 
			
		||||
			Helper(new(Helper)).
 | 
			
		||||
			Prefix("/setup/confirm").
 | 
			
		||||
			GetPost("", new(IndexAction)).
 | 
			
		||||
			EndAll()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -127,6 +127,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	// 安装
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/setup"
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/setup/confirm"
 | 
			
		||||
 | 
			
		||||
	// 平台用户
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										69
									
								
								web/views/@default/setup/confirm/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								web/views/@default/setup/confirm/index.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
.install-box {
 | 
			
		||||
  width: 50em;
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  left: 50%;
 | 
			
		||||
  margin-left: -25em;
 | 
			
		||||
  top: 1em;
 | 
			
		||||
  bottom: 1em;
 | 
			
		||||
  overflow-y: auto;
 | 
			
		||||
}
 | 
			
		||||
.install-box .button.margin {
 | 
			
		||||
  margin-top: 1em;
 | 
			
		||||
}
 | 
			
		||||
.install-box .button.primary {
 | 
			
		||||
  float: right;
 | 
			
		||||
}
 | 
			
		||||
.install-box .button.disabled {
 | 
			
		||||
  float: right;
 | 
			
		||||
}
 | 
			
		||||
.install-box table td.title {
 | 
			
		||||
  width: 10em;
 | 
			
		||||
}
 | 
			
		||||
.install-box .radio {
 | 
			
		||||
  margin-right: 1em;
 | 
			
		||||
}
 | 
			
		||||
.install-box .radio label {
 | 
			
		||||
  cursor: pointer !important;
 | 
			
		||||
  font-size: 0.9em !important;
 | 
			
		||||
}
 | 
			
		||||
.install-box h4 {
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
.install-box .content-box {
 | 
			
		||||
  overflow-y: auto;
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  top: 5em;
 | 
			
		||||
  bottom: 5em;
 | 
			
		||||
  left: 50%;
 | 
			
		||||
  width: 50em;
 | 
			
		||||
  padding-right: 1em;
 | 
			
		||||
  margin-left: -25em;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
}
 | 
			
		||||
.install-box .content-box::-webkit-scrollbar {
 | 
			
		||||
  width: 4px;
 | 
			
		||||
}
 | 
			
		||||
.install-box .button-group {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  left: 50%;
 | 
			
		||||
  margin-left: -25em;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
  width: 50em;
 | 
			
		||||
  bottom: 1em;
 | 
			
		||||
}
 | 
			
		||||
.install-box .button-group button {
 | 
			
		||||
  z-index: 10;
 | 
			
		||||
}
 | 
			
		||||
.install-box .button-group .status-box {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 3em;
 | 
			
		||||
  left: 15em;
 | 
			
		||||
  right: 15em;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  z-index: 0;
 | 
			
		||||
}
 | 
			
		||||
.install-box::-webkit-scrollbar {
 | 
			
		||||
  width: 4px;
 | 
			
		||||
}
 | 
			
		||||
/*# sourceMappingURL=index.css.map */
 | 
			
		||||
							
								
								
									
										1
									
								
								web/views/@default/setup/confirm/index.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								web/views/@default/setup/confirm/index.css.map
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EAGC,WAAA;EACA,eAAA;EACA,SAAA;EACA,kBAAA;EACA,QAAA;EACA,WAAA;EACA,gBAAA;;AATD,YAWC,QAAO;EACN,eAAA;;AAZF,YAeC,QAAO;EACN,YAAA;;AAhBF,YAmBC,QAAO;EACN,YAAA;;AApBF,YAuBC,MACC,GAAE;EACD,WAAA;;AAzBH,YA6BC;EACC,iBAAA;;AA9BF,YA6BC,OAGC;EACC,0BAAA;EACA,2BAAA;;AAlCH,YAsCC;EACC,mBAAA;;AAvCF,YA0CC;EACC,gBAAA;EACA,eAAA;EACA,QAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,kBAAA;EACA,kBAAA;EACA,UAAA;;AAnDF,YAsDC,aAAY;EACX,UAAA;;AAvDF,YA0DC;EACC,eAAA;EACA,SAAA;EACA,kBAAA;EACA,UAAA;EACA,WAAA;EACA,WAAA;;AAhEF,YA0DC,cAQC;EACC,WAAA;;AAnEH,YA0DC,cAYC;EACC,kBAAA;EACA,QAAA;EACA,UAAA;EACA,WAAA;EACA,SAAA;EACA,kBAAA;EACA,UAAA;;AAKH,YAAY;EACX,UAAA","file":"index.css"}
 | 
			
		||||
							
								
								
									
										56
									
								
								web/views/@default/setup/confirm/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								web/views/@default/setup/confirm/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
<!doctype html>
 | 
			
		||||
<html lang="zh">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 | 
			
		||||
    <link rel="shortcut icon" href="/images/favicon.png"/>
 | 
			
		||||
    <title>确认GoEdge管理系统</title>
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
 | 
			
		||||
    {$TEA.VUE}
 | 
			
		||||
    {$TEA.SEMANTIC}
 | 
			
		||||
    <script type="text/javascript" src="/js/md5.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="/js/utils.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="/js/sweetalert2/dist/sweetalert2.all.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="/ui/components.js"></script>
 | 
			
		||||
    <link rel="stylesheet" href="/_/@default/@layout.css"/>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
<div class="install-box">
 | 
			
		||||
    <h4>系统发现你可能将管理系统迁移到了新的服务器,为了让系统能正常运行,请做以下确认:</h4>
 | 
			
		||||
 | 
			
		||||
    <form class="ui form" data-tea-action="$" data-tea-before="before" data-tea-done="done" data-tea-success="success">
 | 
			
		||||
        <table class="ui table definition selectable">
 | 
			
		||||
            <tbody v-for="(endpoint, index) in endpoints">
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td class="title">API节点地址<span v-if="endpoints.length > 1">{{index+1}}</span> *</td>
 | 
			
		||||
                    <td>
 | 
			
		||||
                        <input type="text" name="endpoints" v-model="endpoints[index]"/>
 | 
			
		||||
                    </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
            <tbody>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td>NodeId *</td>
 | 
			
		||||
                    <td>
 | 
			
		||||
                        <input type="text" name="nodeId" v-model="nodeId" maxlength="100"/>
 | 
			
		||||
                        <p class="comment">可以在安装时的系统目录下<code-label>configs/api.yaml</code-label>文件中找到。</p>
 | 
			
		||||
                    </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td>Secret *</td>
 | 
			
		||||
                    <td>
 | 
			
		||||
                        <input type="text" name="secret" v-model="secret" maxlength="100"/>
 | 
			
		||||
                        <p class="comment">可以在安装时的系统目录下<code-label>configs/api.yaml</code-label>文件中找到。</p>
 | 
			
		||||
                    </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
 | 
			
		||||
        <div class="margin" style="margin-top: 2em"></div>
 | 
			
		||||
        <button class="ui button primary" type="submit" v-if="!isRequesting">确认</button>
 | 
			
		||||
        <button class="ui button disabled" type="button" v-if="isRequesting">检查中...</button>
 | 
			
		||||
    </form>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										17
									
								
								web/views/@default/setup/confirm/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								web/views/@default/setup/confirm/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.isRequesting = false
 | 
			
		||||
 | 
			
		||||
	this.success = function () {
 | 
			
		||||
		teaweb.success("完成确认,现在跳转到首页", function () {
 | 
			
		||||
			window.location = "/"
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.before = function () {
 | 
			
		||||
		this.isRequesting = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.done = function () {
 | 
			
		||||
		this.isRequesting = false
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										85
									
								
								web/views/@default/setup/confirm/index.less
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								web/views/@default/setup/confirm/index.less
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
.install-box {
 | 
			
		||||
	@width: 50em;
 | 
			
		||||
 | 
			
		||||
	width: @width;
 | 
			
		||||
	position: fixed;
 | 
			
		||||
	left: 50%;
 | 
			
		||||
	margin-left: -@width/2;
 | 
			
		||||
	top: 1em;
 | 
			
		||||
	bottom: 1em;
 | 
			
		||||
	overflow-y: auto;
 | 
			
		||||
 | 
			
		||||
	.button.margin {
 | 
			
		||||
		margin-top: 1em;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.button.primary {
 | 
			
		||||
		float: right;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.button.disabled {
 | 
			
		||||
		float: right;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	table {
 | 
			
		||||
		td.title {
 | 
			
		||||
			width: 10em;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.radio {
 | 
			
		||||
		margin-right: 1em;
 | 
			
		||||
 | 
			
		||||
		label {
 | 
			
		||||
			cursor: pointer !important;
 | 
			
		||||
			font-size: 0.9em !important;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h4 {
 | 
			
		||||
		font-weight: normal;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.content-box {
 | 
			
		||||
		overflow-y: auto;
 | 
			
		||||
		position: fixed;
 | 
			
		||||
		top: 5em;
 | 
			
		||||
		bottom: 5em;
 | 
			
		||||
		left: 50%;
 | 
			
		||||
		width: @width;
 | 
			
		||||
		padding-right: 1em;
 | 
			
		||||
		margin-left: -@width/2;
 | 
			
		||||
		z-index: 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.content-box::-webkit-scrollbar {
 | 
			
		||||
		width: 4px;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.button-group {
 | 
			
		||||
		position: fixed;
 | 
			
		||||
		left: 50%;
 | 
			
		||||
		margin-left: -@width/2;
 | 
			
		||||
		z-index: 1;
 | 
			
		||||
		width: @width;
 | 
			
		||||
		bottom: 1em;
 | 
			
		||||
 | 
			
		||||
		button {
 | 
			
		||||
			z-index: 10;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		.status-box {
 | 
			
		||||
			position: absolute;
 | 
			
		||||
			top: 3em;
 | 
			
		||||
			left: 15em;
 | 
			
		||||
			right: 15em;
 | 
			
		||||
			bottom: 0;
 | 
			
		||||
			text-align: center;
 | 
			
		||||
			z-index: 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.install-box::-webkit-scrollbar {
 | 
			
		||||
	width: 4px;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user