diff options
author | Mike Crute <mike@crute.us> | 2021-11-24 12:00:07 -0800 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2021-11-24 12:10:53 -0800 |
commit | a7646122d8e0a82cbf9c8b81451c28fbc650c8f6 (patch) | |
tree | 622d21740b2aa0fe29ee81b56aa43a59fe8b89d0 | |
parent | bb96127a71d3d22825a35ffc6b6c8bea0590f202 (diff) | |
download | cloud-identity-broker-a7646122d8e0a82cbf9c8b81451c28fbc650c8f6.tar.bz2 cloud-identity-broker-a7646122d8e0a82cbf9c8b81451c28fbc650c8f6.tar.xz cloud-identity-broker-a7646122d8e0a82cbf9c8b81451c28fbc650c8f6.zip |
Cleanup index template
-rw-r--r-- | templates/assets/site.css | 46 | ||||
-rw-r--r-- | templates/assets/site.js | 51 | ||||
-rw-r--r-- | templates/index.tpl | 17 |
3 files changed, 79 insertions, 35 deletions
diff --git a/templates/assets/site.css b/templates/assets/site.css index 65fb4ce..df1bab8 100644 --- a/templates/assets/site.css +++ b/templates/assets/site.css | |||
@@ -35,6 +35,15 @@ tt { | |||
35 | border: 1px solid #999; | 35 | border: 1px solid #999; |
36 | padding: 0.25em; | 36 | padding: 0.25em; |
37 | } | 37 | } |
38 | #username { | ||
39 | font-weight: bolder; | ||
40 | } | ||
41 | #login-row { | ||
42 | text-align: right; | ||
43 | } | ||
44 | #api-key-block { | ||
45 | display: none; | ||
46 | } | ||
38 | #api-key { | 47 | #api-key { |
39 | margin: auto; | 48 | margin: auto; |
40 | } | 49 | } |
@@ -43,13 +52,26 @@ tt { | |||
43 | } | 52 | } |
44 | #api-error { | 53 | #api-error { |
45 | border: 0.25em solid red; | 54 | border: 0.25em solid red; |
46 | color: white; | 55 | color: yellow; |
47 | font-size: 2em; | 56 | font-size: 2em; |
48 | background-color: #ff8080; | 57 | background-color: #ff8080; |
49 | padding: 1em; | 58 | padding: 1em; |
50 | text-align: center; | 59 | text-align: center; |
51 | display: none; | 60 | display: none; |
52 | } | 61 | } |
62 | #api-error .sub-message { | ||
63 | font-size: 1rem; | ||
64 | color: white; | ||
65 | } | ||
66 | #api-success { | ||
67 | border: 0.25em solid green; | ||
68 | color: green; | ||
69 | font-size: 2em; | ||
70 | background-color: #00ff80; | ||
71 | padding: 1em; | ||
72 | text-align: center; | ||
73 | display: none; | ||
74 | } | ||
53 | #account-table tr td:nth-child(2), | 75 | #account-table tr td:nth-child(2), |
54 | #account-table tr td:nth-child(3) { | 76 | #account-table tr td:nth-child(3) { |
55 | text-align: center; | 77 | text-align: center; |
@@ -60,3 +82,25 @@ tt { | |||
60 | body.isAdmin .admin { | 82 | body.isAdmin .admin { |
61 | display: initial; | 83 | display: initial; |
62 | } | 84 | } |
85 | .tag { | ||
86 | display: block; | ||
87 | float: right; | ||
88 | color: white; | ||
89 | font-size: 0.8em; | ||
90 | border-radius: 0.3em; | ||
91 | padding: 0.2em 0.5em; | ||
92 | cursor: default; | ||
93 | } | ||
94 | .vendor-aws { | ||
95 | background-color: orange; | ||
96 | } | ||
97 | .vendor-gcp { | ||
98 | background-color: blue; | ||
99 | } | ||
100 | .vendor-oci { | ||
101 | background-color: red; | ||
102 | } | ||
103 | .vendor-azure { | ||
104 | color: black; | ||
105 | background-color: lightblue; | ||
106 | } | ||
diff --git a/templates/assets/site.js b/templates/assets/site.js index ebf9f5f..7ba4b15 100644 --- a/templates/assets/site.js +++ b/templates/assets/site.js | |||
@@ -1,12 +1,12 @@ | |||
1 | function fillTemplate(templateId, values) { | 1 | function fillTemplate(templateId, values) { |
2 | var tpl = document.getElementById(templateId).text; | 2 | var tpl = document.getElementById(templateId).text; |
3 | 3 | ||
4 | Object.keys(values).forEach(function(key) { | 4 | Object.keys(values).forEach(key => { |
5 | tpl = tpl.replace(new RegExp("\\[\\[ \\." + key + " \\]\\]", "g"), values[key]); | 5 | tpl = tpl.replace(new RegExp("\\[\\[ \\." + key + " \\]\\]", "g"), values[key]); |
6 | }); | 6 | }); |
7 | 7 | ||
8 | var out = []; | 8 | var out = []; |
9 | tpl.split("\n").forEach(function(line) { | 9 | tpl.split("\n").forEach(line => { |
10 | line = line.replace(/^\s+/, "").replace(/\s+$/, ""); | 10 | line = line.replace(/^\s+/, "").replace(/\s+$/, ""); |
11 | if (line !== "") { | 11 | if (line !== "") { |
12 | out.push(line); | 12 | out.push(line); |
@@ -43,7 +43,7 @@ function accountTableLinkClick(event) { | |||
43 | "headers": { | 43 | "headers": { |
44 | "Accept": event.target.dataset["contentType"] | 44 | "Accept": event.target.dataset["contentType"] |
45 | } | 45 | } |
46 | }).then(r => r.text()).then(function(text) { | 46 | }).then(r => r.text()).then(text => { |
47 | var newTr = fillTemplate("credential_row_template", { | 47 | var newTr = fillTemplate("credential_row_template", { |
48 | "Account": account, | 48 | "Account": account, |
49 | "Content": text, | 49 | "Content": text, |
@@ -51,25 +51,19 @@ function accountTableLinkClick(event) { | |||
51 | 51 | ||
52 | event.target.text = oldText; | 52 | event.target.text = oldText; |
53 | thisRow.insertAdjacentHTML("afterend", newTr); | 53 | thisRow.insertAdjacentHTML("afterend", newTr); |
54 | thisRow.nextElementSibling.getElementsByTagName("button")[0].addEventListener("click", function(event) { | 54 | thisRow.nextElementSibling.getElementsByTagName("button")[0].addEventListener("click", e => { |
55 | event.target.parentNode.parentNode.remove(); | 55 | e.target.parentNode.parentNode.remove(); |
56 | }); | 56 | }); |
57 | }); | 57 | }); |
58 | 58 | ||
59 | return false; | 59 | return false; |
60 | } | 60 | } |
61 | 61 | ||
62 | function populateAccountTable() { | ||
63 | fetch("/api/account").then(getJSON).then(function(response) { | ||
64 | response.forEach(populateAccountRow); | ||
65 | }); | ||
66 | } | ||
67 | |||
68 | function populateAccountRow(row) { | 62 | function populateAccountRow(row) { |
69 | var out = fillTemplate("account_row_template", row); | 63 | document.querySelector("#account-table tr").insertAdjacentHTML("afterend", |
70 | document.querySelector("#account-table tr").insertAdjacentHTML("afterend", out); | 64 | fillTemplate(row["vendor"] + "_account_row_template", row)); |
71 | 65 | ||
72 | document.querySelectorAll(".account-row a[data-content-type]").forEach(function(e) { | 66 | document.querySelectorAll(".account-row a[data-content-type]").forEach(e => { |
73 | e.addEventListener("click", accountTableLinkClick); | 67 | e.addEventListener("click", accountTableLinkClick); |
74 | }); | 68 | }); |
75 | } | 69 | } |
@@ -78,25 +72,30 @@ function getCookie(name) { | |||
78 | return document.cookie.match(new RegExp(name + "=\"?([^;\"]*)\"?;?"))[1]; | 72 | return document.cookie.match(new RegExp(name + "=\"?([^;\"]*)\"?;?"))[1]; |
79 | } | 73 | } |
80 | 74 | ||
81 | function parseJWT(token) { | 75 | function parseJWT() { |
82 | return JSON.parse(atob(token.split(".")[1])); | 76 | return JSON.parse(atob(getCookie("github-token").split(".")[1])); |
83 | } | 77 | } |
84 | 78 | ||
85 | function parseJWTExpires(token) { | 79 | function parseJWTExpires() { |
86 | return new Date(parseJWT(token)["exp"] * 1000); | 80 | return new Date(parseJWT()["exp"] * 1000); |
87 | } | 81 | } |
88 | 82 | ||
89 | function isAdmin(token) { | 83 | function isAdmin() { |
90 | return parseJWT(token)["admin"]; | 84 | return parseJWT()["admin"]; |
91 | } | 85 | } |
92 | 86 | ||
93 | function populateAPIKey() { | 87 | function setupHomePage() { |
94 | document.querySelector("#api-key textarea").innerText = getCookie("github-token"); | 88 | fetch("/api/account").then(getJSON).then(r => r.forEach(populateAccountRow)); |
95 | document.querySelector("#session-expires").innerText = parseJWTExpires(getCookie("github-token")); | ||
96 | } | ||
97 | 89 | ||
98 | function setAdminClass() { | 90 | document.getElementById("username").innerText = parseJWT()["sub"]; |
99 | if (isAdmin(getCookie("github-token"))) { | 91 | |
92 | if (isAdmin()) { | ||
100 | document.body.classList.add("isAdmin"); | 93 | document.body.classList.add("isAdmin"); |
101 | } | 94 | } |
95 | |||
96 | document.getElementById("show-api-key").addEventListener("click", _ => { | ||
97 | document.querySelector("#api-key textarea").innerText = getCookie("github-token"); | ||
98 | document.querySelector("#session-expires").innerText = parseJWTExpires(); | ||
99 | document.getElementById("api-key-block").style.display = "block"; | ||
100 | }); | ||
102 | } | 101 | } |
diff --git a/templates/index.tpl b/templates/index.tpl index c8c95d4..9baef2a 100644 --- a/templates/index.tpl +++ b/templates/index.tpl | |||
@@ -12,10 +12,9 @@ | |||
12 | </td> | 12 | </td> |
13 | </tr> | 13 | </tr> |
14 | </script> | 14 | </script> |
15 | <script id="account_row_template" type="text/template"> | 15 | <script id="aws_account_row_template" type="text/template"> |
16 | <tr id="account-row-[[ .short_name ]]" class="account-row" data-account-name="[[ .short_name ]]" data-global-credential-endpoint="[[ .global_credential_url ]]"> | 16 | <tr id="account-row-[[ .short_name ]]" class="account-row" data-account-name="[[ .short_name ]]" data-global-credential-endpoint="[[ .global_credential_url ]]"> |
17 | <td>[[ .name ]]</td> | 17 | <td>[[ .name ]] <span class="vendor-tag vendor-[[ .vendor ]]" alt="[[ .vendor ]]" title="[[ .vendor ]]">[[ .vendor ]]</span></td> |
18 | <td>[[ .vendor ]]</td> | ||
19 | <td> | 18 | <td> |
20 | <a href="[[ .console_redirect_url ]]">Console</a> | | 19 | <a href="[[ .console_redirect_url ]]">Console</a> | |
21 | <a data-content-type="application/vnd.broker.v2.credential.aws.ini" href="#/cli/[[ .short_name ]]">AWS CLI</a> | | 20 | <a data-content-type="application/vnd.broker.v2.credential.aws.ini" href="#/cli/[[ .short_name ]]">AWS CLI</a> | |
@@ -27,29 +26,31 @@ | |||
27 | </script> | 26 | </script> |
28 | <script type="text/javascript" src="/assets/site.js"></script> | 27 | <script type="text/javascript" src="/assets/site.js"></script> |
29 | <script type="text/javascript"> | 28 | <script type="text/javascript"> |
30 | window.addEventListener('load', populateAPIKey); | 29 | window.addEventListener('load', setupHomePage); |
31 | window.addEventListener('load', populateAccountTable); | ||
32 | window.addEventListener('load', setAdminClass); | ||
33 | </script> | 30 | </script> |
34 | </head> | 31 | </head> |
35 | <body> | 32 | <body> |
36 | <p id="api-error">Error communicating with the API.</p> | 33 | <p id="api-error">Error communicating with the API.</p> |
37 | 34 | ||
35 | <div id="login-row"> | ||
36 | Hello <span id="username"></span>! (<a href="/api">API</a> | <a href="#" id="show-api-key">API Key</a> | <a href="/logout">Logout</a>) | ||
37 | </div> | ||
38 | |||
38 | <h1>Cloud Accounts</h1> | 39 | <h1>Cloud Accounts</h1> |
39 | <table id="account-table"> | 40 | <table id="account-table"> |
40 | <tr> | 41 | <tr> |
41 | <th>Console Login</th> | 42 | <th>Console Login</th> |
42 | <th>Vendor</th> | ||
43 | <th>Credentials</th> | 43 | <th>Credentials</th> |
44 | </tr> | 44 | </tr> |
45 | </table> | 45 | </table> |
46 | <p><button class="admin">Add Account</button></p> | ||
47 | 46 | ||
47 | <div id="api-key-block"> | ||
48 | <h1>API Key</h1> | 48 | <h1>API Key</h1> |
49 | <div id="api-key"> | 49 | <div id="api-key"> |
50 | <p>To access <a href="/api/account">the API</a> set the header <tt>Authorization: Bearer {token}</tt> to the token below:</p> | 50 | <p>To access <a href="/api/account">the API</a> set the header <tt>Authorization: Bearer {token}</tt> to the token below:</p> |
51 | <textarea>Bearer {token}</textarea> | 51 | <textarea>Bearer {token}</textarea> |
52 | <p><b>Token Expires:</b> <span id="session-expires"></span></p> | 52 | <p><b>Token Expires:</b> <span id="session-expires"></span></p> |
53 | </div> | 53 | </div> |
54 | </div> | ||
54 | </body> | 55 | </body> |
55 | </html> | 56 | </html> |