зеркало из https://github.com/Azure/ARO-RP.git
Родитель
162164ea66
Коммит
27bc205e24
|
@ -225,20 +225,6 @@
|
|||
"expirationDate": null,
|
||||
"type": null
|
||||
},
|
||||
"20cd31403587ea29d121d28ac3ef7d9b6a7b922baaf817f79ba4ccf0d5730b43": {
|
||||
"signature": "20cd31403587ea29d121d28ac3ef7d9b6a7b922baaf817f79ba4ccf0d5730b43",
|
||||
"alternativeSignatures": [],
|
||||
"target": "portal/v1/build/main.js.LICENSE.txt",
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"tool": "policheck",
|
||||
"ruleId": "166862",
|
||||
"justification": null,
|
||||
"createdDate": "2022-07-14 16:28:44Z",
|
||||
"expirationDate": null,
|
||||
"type": null
|
||||
},
|
||||
"9c277a79f4467e0f7fc8eaeac774f9680776f80a1acfee7a0e3331dde2f7ef6d": {
|
||||
"signature": "9c277a79f4467e0f7fc8eaeac774f9680776f80a1acfee7a0e3331dde2f7ef6d",
|
||||
"alternativeSignatures": [],
|
||||
|
|
2
Makefile
2
Makefile
|
@ -167,7 +167,7 @@ run-portal:
|
|||
go run -ldflags "-X github.com/Azure/ARO-RP/pkg/util/version.GitCommit=$(VERSION)" ./cmd/aro portal
|
||||
|
||||
build-portal:
|
||||
cd portal/v1 && npm install && npm run build && cd ../v2 && npm install && npm run build
|
||||
cd portal/v2 && npm install && npm run build
|
||||
|
||||
pyenv:
|
||||
python3 -m venv pyenv
|
||||
|
|
|
@ -10,7 +10,7 @@ The front end is developed using react and typescript. The back end api is writt
|
|||
|
||||
The portal front end lives in the top level directory of the ARO-RP repo within the `portal` directory. The portal back end exists within `pkg/portal`
|
||||
|
||||
The front end code is compiled into go code using the bindata golang module. This front end code is then served through the RP.
|
||||
The front end code is built into the `aro` binary (via go embed) and the static files are served by `aro portal`.
|
||||
|
||||
The admin portal also serves a static Prometheus web frontend. The contents are taken from a Prometheus release's web-ui artifact (e.g. [2.48](https://github.com/prometheus/prometheus/releases/download/v2.48.0/prometheus-web-ui-2.48.0.tar.gz)), and the static/react subdirectory is mirrored to this repository's pkg/portal/assets/prometheus-ui directory.
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"embed"
|
||||
)
|
||||
|
||||
//go:embed v1/*
|
||||
//go:embed v2/*
|
||||
//go:embed prometheus-ui/*
|
||||
var EmbeddedFiles embed.FS
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<title>ARO SRE portal ({{ .location }})</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar bg-light shadow-sm">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-brand">
|
||||
<strong>ARO SRE portal ({{ .location }})</strong>
|
||||
</div>
|
||||
<div>
|
||||
<a href="/" class="btn btn-secondary" id="btnV2">Admin Portal V2</a>
|
||||
<button class="btn btn-secondary" id="btnLogout">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container py-4">
|
||||
<div class="form-group">
|
||||
<label for="selResourceId" class="form-label">Cluster:</label>
|
||||
<div class="mb-3">
|
||||
<select id="selResourceId" autocomplete="off" placeholder="Search clusters..." disabled>
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="selMaster" class="form-label">Master:</label>
|
||||
<div class="mb-3">
|
||||
<select class="form-select" id="selMaster">
|
||||
<option value="0" selected>master-0</option>
|
||||
<option value="1">master-1</option>
|
||||
<option value="2">master-2</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-secondary" id="btnPrometheus">Prometheus</button>
|
||||
|
||||
<button class="btn btn-secondary" id="btnKubeconfig">Kubeconfig</button>
|
||||
|
||||
<button class="btn btn-secondary" id="btnSSH">SSH</button>
|
||||
|
||||
<div class="py-4" id="divAlerts"></div>
|
||||
</div>
|
||||
|
||||
<template id="tmplSSHAlert">
|
||||
<div class="alert alert-primary alert-dismissible fade show" role="alert">
|
||||
<div>
|
||||
<button class="btn btn-secondary copy-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="18px" height="18px">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
|
||||
</svg>
|
||||
</button>
|
||||
<span data-copy="command">Command: <code></code></span>
|
||||
</div>
|
||||
<div class="py-2">
|
||||
<button class="btn btn-secondary copy-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="18px" height="18px">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
|
||||
</svg>
|
||||
</button>
|
||||
<span data-copy="password">Password: <code></code></span>
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="tmplSSHAlertError">
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<span data-copy="error"></span>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
{{ .csrfField }}
|
||||
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,84 +0,0 @@
|
|||
/*!
|
||||
* Bootstrap alert.js v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Bootstrap base-component.js v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Bootstrap component-functions.js v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Bootstrap config.js v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Bootstrap data.js v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Bootstrap dropdown.js v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Bootstrap event-handler.js v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Bootstrap index.js v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Bootstrap manipulator.js v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Bootstrap selector-engine.js v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Sizzle CSS Selector Engine v2.3.6
|
||||
* https://sizzlejs.com/
|
||||
*
|
||||
* Copyright JS Foundation and other contributors
|
||||
* Released under the MIT license
|
||||
* https://js.foundation/
|
||||
*
|
||||
* Date: 2021-02-16
|
||||
*/
|
||||
|
||||
/*!
|
||||
* jQuery JavaScript Library v3.6.1
|
||||
* https://jquery.com/
|
||||
*
|
||||
* Includes Sizzle.js
|
||||
* https://sizzlejs.com/
|
||||
*
|
||||
* Copyright OpenJS Foundation and other contributors
|
||||
* Released under the MIT license
|
||||
* https://jquery.org/license
|
||||
*
|
||||
* Date: 2022-08-26T17:52Z
|
||||
*/
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"files": {
|
||||
"main.js": "/static/js/main.09fbc574.js",
|
||||
"main.js": "/static/js/main.662aea13.js",
|
||||
"index.html": "/index.html",
|
||||
"main.09fbc574.js.map": "/static/js/main.09fbc574.js.map"
|
||||
"main.662aea13.js.map": "/static/js/main.662aea13.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/js/main.09fbc574.js"
|
||||
"static/js/main.662aea13.js"
|
||||
]
|
||||
}
|
|
@ -1 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>ARO Portal</title><script defer="defer" src="/static/js/main.09fbc574.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>ARO Portal</title><script defer="defer" src="/static/js/main.662aea13.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -69,7 +69,6 @@ type portal struct {
|
|||
|
||||
dialer proxy.Dialer
|
||||
|
||||
templateV1 *template.Template
|
||||
templateV2 *template.Template
|
||||
templatePrometheus *template.Template
|
||||
|
||||
|
@ -134,11 +133,6 @@ func (p *portal) setupRouter(kconfig *kubeconfig.Kubeconfig, prom *prometheus.Pr
|
|||
r := mux.NewRouter()
|
||||
r.Use(middleware.Panic(p.log))
|
||||
|
||||
assetv1, err := assets.EmbeddedFiles.ReadFile("v1/build/index.html")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
assetv2, err := assets.EmbeddedFiles.ReadFile("v2/build/index.html")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -149,11 +143,6 @@ func (p *portal) setupRouter(kconfig *kubeconfig.Kubeconfig, prom *prometheus.Pr
|
|||
return nil, err
|
||||
}
|
||||
|
||||
p.templateV1, err = template.New("index.html").Parse(string(assetv1))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.templateV2, err = template.New("index.html").Parse(string(assetv2))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -325,39 +314,20 @@ func (p *portal) aadAuthenticatedRoutes(r *mux.Router, prom *prometheus.Promethe
|
|||
r.Methods(http.MethodPost).Path("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/microsoft.redhatopenshift/openshiftclusters/{resourceName}/ssh/new").HandlerFunc(sshStruct.New)
|
||||
|
||||
for _, name := range names {
|
||||
regexp, _ := regexp.Compile(`v[1,2]/build/.*\..*`)
|
||||
regexp, _ := regexp.Compile(`v2/build/.*\..*`)
|
||||
name := regexp.FindString(name)
|
||||
switch name {
|
||||
case "v2/build/index.html":
|
||||
r.Methods(http.MethodGet).Path("/").HandlerFunc(p.indexV2)
|
||||
r.Methods(http.MethodGet).PathPrefix("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/microsoft.redhatopenshift/openshiftclusters/{resourceName}").HandlerFunc(p.indexV2)
|
||||
case "v1/build/index.html":
|
||||
r.Methods(http.MethodGet).Path("/v1").HandlerFunc(p.index)
|
||||
case "":
|
||||
default:
|
||||
fmtName := strings.TrimPrefix(name, "v1/build/")
|
||||
fmtName = strings.TrimPrefix(fmtName, "v2/build/")
|
||||
|
||||
fmtName := strings.TrimPrefix(name, "v2/build/")
|
||||
r.Methods(http.MethodGet).Path("/" + fmtName).HandlerFunc(p.serve(name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *portal) index(w http.ResponseWriter, r *http.Request) {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := p.templateV1.ExecuteTemplate(buf, "index.html", map[string]interface{}{
|
||||
"location": p.env.Location(),
|
||||
csrf.TemplateTag: csrf.TemplateField(r),
|
||||
})
|
||||
if err != nil {
|
||||
p.internalServerError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
http.ServeContent(w, r, "index.html", time.Time{}, bytes.NewReader(buf.Bytes()))
|
||||
}
|
||||
|
||||
func (p *portal) indexV2(w http.ResponseWriter, r *http.Request) {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
|
|
|
@ -123,15 +123,15 @@ func TestSecurity(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "/main.js",
|
||||
name: "/asset-manifest.json",
|
||||
request: func() (*http.Request, error) {
|
||||
return http.NewRequest(http.MethodGet, "https://server/main.js", nil)
|
||||
return http.NewRequest(http.MethodGet, "https://server/asset-manifest.json", nil)
|
||||
},
|
||||
wantAuditOperation: "GET /main.js",
|
||||
wantAuditOperation: "GET /asset-manifest.json",
|
||||
wantAuditTargetResources: []audit.TargetResource{
|
||||
{
|
||||
TargetResourceType: "",
|
||||
TargetResourceName: "/main.js",
|
||||
TargetResourceName: "/asset-manifest.json",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -359,7 +359,7 @@ func TestSecurity(t *testing.T) {
|
|||
// the Payload will change during this access, resulting in the e2e panicking.
|
||||
// `go test -race -timeout 30s -run ^TestSecurity$ ./pkg/portal` should show the race and
|
||||
// where the concurrent read/write is occurring.
|
||||
if tt.name == "/" || tt.name == "/main.js" {
|
||||
if tt.name == "/" || tt.name == "/asset-manifest.json" {
|
||||
err = testpoller.Poll(1*time.Second, 5*time.Millisecond, func() (bool, error) {
|
||||
if len(auditHook.AllEntries()) == 1 {
|
||||
if _, ok := auditHook.AllEntries()[0].Data[audit.MetadataPayload]; ok {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
"name": "aro-rp",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "webpack --config webpack.prod.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Microsoft",
|
||||
"license": "Apache2",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"bootstrap": "^5.2.2",
|
||||
"jquery": "^3.6.1",
|
||||
"tom-select": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"css-loader": "^6.7.1",
|
||||
"css-minimizer-webpack-plugin": "^5.0.0",
|
||||
"exports-loader": "^4.0.0",
|
||||
"html-webpack-plugin": "^5.3.1",
|
||||
"mini-css-extract-plugin": "^2.6.1",
|
||||
"style-loader": "^3.3.1",
|
||||
"webpack": "^5.76.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-server": "^4.11.0",
|
||||
"webpack-merge": "^5.7.3"
|
||||
},
|
||||
"overrides": {
|
||||
"minimatch": "^5.1.0"
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<title>ARO SRE portal ({{ .location }})</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar bg-light shadow-sm">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-brand">
|
||||
<strong>ARO SRE portal ({{ .location }})</strong>
|
||||
</div>
|
||||
<div>
|
||||
<a href="/" class="btn btn-secondary" id="btnV2">Admin Portal V2</a>
|
||||
<button class="btn btn-secondary" id="btnLogout">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container py-4">
|
||||
<div class="form-group">
|
||||
<label for="selResourceId" class="form-label">Cluster:</label>
|
||||
<div class="mb-3">
|
||||
<select id="selResourceId" autocomplete="off" placeholder="Search clusters..." disabled>
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="selMaster" class="form-label">Master:</label>
|
||||
<div class="mb-3">
|
||||
<select class="form-select" id="selMaster">
|
||||
<option value="0" selected>master-0</option>
|
||||
<option value="1">master-1</option>
|
||||
<option value="2">master-2</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-secondary" id="btnPrometheus">Prometheus</button>
|
||||
|
||||
<button class="btn btn-secondary" id="btnKubeconfig">Kubeconfig</button>
|
||||
|
||||
<button class="btn btn-secondary" id="btnSSH">SSH</button>
|
||||
|
||||
<div class="py-4" id="divAlerts"></div>
|
||||
</div>
|
||||
|
||||
<template id="tmplSSHAlert">
|
||||
<div class="alert alert-primary alert-dismissible fade show" role="alert">
|
||||
<div>
|
||||
<button class="btn btn-secondary copy-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="18px" height="18px">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
|
||||
</svg>
|
||||
</button>
|
||||
<span data-copy="command">Command: <code></code></span>
|
||||
</div>
|
||||
<div class="py-2">
|
||||
<button class="btn btn-secondary copy-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="18px" height="18px">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
|
||||
</svg>
|
||||
</button>
|
||||
<span data-copy="password">Password: <code></code></span>
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="tmplSSHAlertError">
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<span data-copy="error"></span>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
{{ .csrfField }}
|
||||
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,117 +0,0 @@
|
|||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
|
||||
import 'bootstrap/js/dist/util';
|
||||
import 'bootstrap/js/dist/dropdown';
|
||||
import 'bootstrap/js/dist/alert';
|
||||
|
||||
import "./select/select.css"
|
||||
import 'tom-select/dist/css/tom-select.bootstrap5.min.css';
|
||||
import TomSelect from 'tom-select/dist/js/tom-select.complete.min';
|
||||
|
||||
jQuery.extend({
|
||||
redirect: function (location, args) {
|
||||
var form = $("<form method='POST' style='display: none;'></form>");
|
||||
form.attr("action", location);
|
||||
|
||||
$.each(args || {}, function (key, value) {
|
||||
var input = $("<input name='hidden'></input>");
|
||||
|
||||
input.attr("name", key);
|
||||
input.attr("value", value);
|
||||
|
||||
form.append(input);
|
||||
});
|
||||
|
||||
form.append($("input[name='gorilla.csrf.Token']").first());
|
||||
form.appendTo("body").submit();
|
||||
}
|
||||
});
|
||||
|
||||
jQuery(function () {
|
||||
$.ajax({
|
||||
url: "/api/clusters",
|
||||
success: function (clusters) {
|
||||
$.each(clusters, function (i, cluster) {
|
||||
$("#selResourceId").append($("<option>").text(cluster.resourceId));
|
||||
});
|
||||
|
||||
$("#selResourceId").prop("disabled", false);
|
||||
|
||||
new TomSelect("#selResourceId", {
|
||||
plugins: ["dropdown_input"],
|
||||
maxOptions: null,
|
||||
maxItems: 1,
|
||||
placeholder: "Search clusters...",
|
||||
onDropdownOpen: function (value) {
|
||||
$(".dropdown-input").val($(".ts-control").children("div").html());
|
||||
}
|
||||
});
|
||||
|
||||
$("#selResourceId").css("display", "none");
|
||||
},
|
||||
dataType: "json",
|
||||
});
|
||||
|
||||
$("#btnLogout").click(function () {
|
||||
$.redirect("/api/logout");
|
||||
});
|
||||
|
||||
$("#btnKubeconfig").click(function () {
|
||||
$.redirect($("#selResourceId").val() + "/kubeconfig/new");
|
||||
});
|
||||
|
||||
$("#btnPrometheus").click(function () {
|
||||
window.location = $("#selResourceId").val() + "/prometheus";
|
||||
});
|
||||
|
||||
$("#btnSSH").click(function () {
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: $("#selResourceId").val() + "/ssh/new",
|
||||
headers: {
|
||||
"X-CSRF-Token": $("input[name='gorilla.csrf.Token']").val(),
|
||||
},
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify({
|
||||
"master": parseInt($("#selMaster").val()),
|
||||
}),
|
||||
success: function (reply) {
|
||||
if (reply["error"]) {
|
||||
var template = $("#tmplSSHAlertError").html();
|
||||
var alert = $(template);
|
||||
|
||||
alert.find("span[data-copy='error']").text(reply["error"]);
|
||||
$("#divAlerts").html(alert);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var template = $("#tmplSSHAlert").html();
|
||||
var alert = $(template);
|
||||
|
||||
alert.find("span[data-copy='command'] > code").text(reply["command"]);
|
||||
alert.find("span[data-copy='command']").attr("data-copy", reply["command"]);
|
||||
alert.find("span[data-copy='password'] > code").text("********");
|
||||
alert.find("span[data-copy='password']").attr("data-copy", reply["password"]);
|
||||
$("#divAlerts").html(alert);
|
||||
|
||||
$('.copy-button').click(function () {
|
||||
var textarea = $("<textarea class='style: hidden;' id='textarea'></textarea>");
|
||||
textarea.text($(this).next().attr("data-copy"));
|
||||
textarea.appendTo("body");
|
||||
|
||||
textarea = document.getElementById("textarea")
|
||||
textarea.select();
|
||||
textarea.setSelectionRange(0, textarea.value.length + 1);
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textarea)
|
||||
});
|
||||
},
|
||||
dataType: "json",
|
||||
});
|
||||
});
|
||||
|
||||
$("#btnV2").click(function () {
|
||||
window.location = "/";
|
||||
});
|
||||
});
|
|
@ -1,23 +0,0 @@
|
|||
.ts-control .item {
|
||||
white-space: nowrap;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.ts-dropdown [data-selectable].option {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.ts-dropdown-content {
|
||||
overflow: auto !important;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#selResourceId {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ts-wrapper:not(.form-control):not(.form-select).single .ts-control {
|
||||
background: none !important;
|
||||
overflow-x: auto;
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.js',
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
path: path.resolve(__dirname, '../../pkg/portal/assets/v1/', 'build'),
|
||||
clean: true,
|
||||
},
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin(),
|
||||
new webpack.ProvidePlugin({
|
||||
$: 'jquery',
|
||||
jQuery: 'jquery',
|
||||
}),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: "src/index.html", to: "index.html" },
|
||||
],
|
||||
}),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.s?css$/i,
|
||||
use: [MiniCssExtractPlugin.loader, 'css-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
minimizer: [
|
||||
`...`,
|
||||
new CssMinimizerPlugin(),
|
||||
],
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
styles: {
|
||||
name: 'styles',
|
||||
type: 'css/mini-extract',
|
||||
chunks: 'all',
|
||||
enforce: true,
|
||||
},
|
||||
defaultVendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
priority: -10,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
default: {
|
||||
minChunks: 2,
|
||||
priority: -20,
|
||||
reuseExistingChunk: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const fs = require('fs');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'development',
|
||||
devtool: 'source-map',
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
});
|
|
@ -22,7 +22,6 @@ import {
|
|||
Icon,
|
||||
mergeStyleSets,
|
||||
registerIcons,
|
||||
DefaultButton,
|
||||
} from "@fluentui/react"
|
||||
import { AxiosResponse } from "axios"
|
||||
import { useBoolean } from "@fluentui/react-hooks"
|
||||
|
@ -55,9 +54,9 @@ export interface ICluster {
|
|||
|
||||
export interface IClusterCoordinates {
|
||||
subscription: string
|
||||
resourceGroup: string,
|
||||
name: string,
|
||||
resourceId: string,
|
||||
resourceGroup: string
|
||||
name: string
|
||||
resourceId: string
|
||||
}
|
||||
|
||||
const stackStyles: IStackStyles = {
|
||||
|
@ -99,22 +98,6 @@ const MenuButtonStyles: IButtonStyles = {
|
|||
},
|
||||
}
|
||||
|
||||
const v1ButtonStyle: IButtonStyles = {
|
||||
root: {
|
||||
backgroundColor: "transparent",
|
||||
color: DefaultPalette.white,
|
||||
minWidth: "50px",
|
||||
height: "20px",
|
||||
marginLeft: "10px",
|
||||
padding: "0px",
|
||||
borderColor: DefaultPalette.white,
|
||||
},
|
||||
rootHovered: {
|
||||
backgroundColor: DefaultPalette.white,
|
||||
color: DefaultPalette.themePrimary,
|
||||
},
|
||||
}
|
||||
|
||||
const darkTheme: PartialTheme = {
|
||||
semanticColors: {
|
||||
bodyBackground: DefaultPalette.themePrimary,
|
||||
|
@ -309,11 +292,6 @@ function App() {
|
|||
<Icon iconName={"Admin"}></Icon>
|
||||
</TooltipHost>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<DefaultButton styles={v1ButtonStyle} title="Go to Admin Portal V1" href="/v1">
|
||||
V1
|
||||
</DefaultButton>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<IconButton
|
||||
iconProps={{ iconName: "SignOut" }}
|
||||
|
@ -326,24 +304,20 @@ function App() {
|
|||
<Stack styles={contentStackStyles}>
|
||||
<Stack.Item grow>{error && errorBar()}</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<ClusterList
|
||||
csrfToken={csrfRef}
|
||||
sshBox={sshRef}
|
||||
csrfTokenAvailable={fetching}
|
||||
/>
|
||||
<ClusterList csrfToken={csrfRef} sshBox={sshRef} csrfTokenAvailable={fetching} />
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/subscriptions/:subscriptionId/resourcegroups/:resourceGroupName/providers/microsoft.redhatopenshift/openshiftclusters/:resourceName/*?"
|
||||
element={(
|
||||
element={
|
||||
<ClusterDetailPanel
|
||||
csrfToken={csrfRef}
|
||||
sshBox={sshRef}
|
||||
loaded={fetching}
|
||||
onClose={_onCloseDetailPanel}
|
||||
/>
|
||||
)}
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</Stack.Item>
|
||||
|
@ -354,4 +328,4 @@ function App() {
|
|||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
export default App
|
||||
|
|
Загрузка…
Ссылка в новой задаче