Skip to content

Commit

Permalink
Merge pull request #51 from acidlemon/htmx
Browse files Browse the repository at this point in the history
use HTMX!
  • Loading branch information
fujiwara authored Jan 23, 2024
2 parents 95c1501 + ead6be0 commit 78ffe41
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 142 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
Expand All @@ -53,5 +54,6 @@ require (
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fujiwara/go-amzn-oidc v0.0.7 h1:PlvfdGu0QKIy3MHmAsSeHOGpMcPC7k8VTmXtg3y8oBQ=
github.com/fujiwara/go-amzn-oidc v0.0.7/go.mod h1:KwCMzB/xJ+0ehAQ0+ResFXgl5h0xHr1noDrQadqhKVE=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand Down Expand Up @@ -172,6 +174,8 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
126 changes: 67 additions & 59 deletions html/launcher.html
Original file line number Diff line number Diff line change
@@ -1,62 +1,70 @@
{{ template "header" }}

<h1>Launch Container</h1>

<div class="col-md-12">
<form id="launcher" method="POST" action="/launch">
<label for="subdomain" class="col-md-2 text-right">subdomain </label>
<input type="text" name="subdomain" value="" id="subdomain"
class="col-md-5" placeholder="mybranch">
<p class="col-md-5">*Required</p>

{{ range $param := .Parameters }}

<label for="{{ $param.Name }}" class="col-md-2 text-right">{{ $param.Name }} </label>
{{ if $param.Options }}
<select name="{{ $param.Name }}" id="{{ $param.Name }}" class="col-md-5">
{{ range $option := $param.Options }}
<option value="{{ $option.Value }}" {{ if eq $option.Value $param.Default }}selected{{ end }}>{{ or $option.Label
$option.Value }}</option>
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Launch New Task</h5>
</div>
<div class="modal-body">
<form id="launcher-form" method="POST" action="/launch">
<div class="mb-3">
<label for="subdomain" class="form-label">subdomain</label>
<input class="form-control" type="text" name="subdomain" value="" id="subdomain" placeholder="mybranch" required
pattern="[a-zA-Z-][a-zA-Z0-9-]+">
<div class="form-text">*Required</div>
</div>
{{ range $param := .Parameters }}
<div class="mb-3">
<label for="{{ $param.Name }}" class="form-label">{{ $param.Name }}</label>
{{ if $param.Options }}
<select class="form-control" name="{{ $param.Name }}" id="{{ $param.Name }}">
{{ range $option := $param.Options }}
<option value="{{ $option.Value }}" {{ if eq $option.Value $param.Default }}selected{{ end }}>{{ or $option.Label
$option.Value }}</option>
{{ end }}
</select>
{{ else }}
<input class="form-control" type="text" name="{{ $param.Name }}" value="{{ $param.Default }}" id="{{ $param.Name }}"
placeholder="your {{ $param.Name }}" {{ if $param.Required }}required{{ end }} />
{{ end }}
<div class="form-text">
{{ if $param.Required }}*Required{{ else }}(Optional){{ end }}
</div>
<div class="form-text">
{{ $param.Description }}
</div>
</div>
{{ end }}
</select>
{{ else }}
<input type="text" name="{{ $param.Name }}" value="{{ $param.Default }}" id="{{ $param.Name }}" class="col-md-5"
placeholder="your {{ $param.Name }}" />
{{ end }}
<p class="col-md-5">{{ if $param.Required }}*Required {{ else }} (optional) {{ end }}</p>

{{ if $param.Description }}
<span class="col-md-2"></span>
<div class="col-md-10">
<p>{{ $param.Description }}</p>
{{ range $i, $taskdef := .DefaultTaskDefinitions }}
{{ if eq $i 0 }}
<div class="mb-3">
<label for="taskdef" class="col-md-3 text-right">Task Definitions</label>
{{ end }}
<input class="form-control" type="text" name="taskdef" value="{{ $taskdef }}" id="taskdef"
placeholder="arn:aws:ecs:ap-northeast-1:123456789012:task-definition/myapp"
required>
<div class="form-text">*Required</div>
</div>
{{ end }}
<div class="mb-3">
<input type="submit" class="btn btn-primary" value="Launch" hx-post="/launch" id="launch-submit">
</div>
</form>
</div>
<div class="modal-footer">
<button id="close-button" type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
{{ end }}

{{ end }}

{{ range $i, $taskdef := .DefaultTaskDefinitions }}

{{ if eq $i 0 }}

<label for="taskdef" class="col-md-2 text-right">Task Definitions</label>

{{ else }}

<div class="col-md-2"></div>

{{ end }}

<input type="text" name="taskdef" value="{{ $taskdef }}" id="taskdef"
class="col-md-5" placeholder="arn:aws:ecs:ap-northeast-1:123456789012:task-definition/myapp">
<p class="col-md-5">*Required</p>

{{ end }}

<p class="col-md-7"></p>
<p class="col-md-5 text-left">
<input type="submit" class="btn btn-primary">
</p>
</form>
</div>

{{ template "footer" . }}
<script>
document.body.addEventListener('htmx:afterRequest', function (event) {
console.log(event.detail);
if (event.detail.pathInfo.requestPath == '/launch') {
if (event.detail.xhr.status >= 400) {
var responseBody = event.detail.xhr.responseText;
alert('エラーが発生しました: ' + responseBody);
} else {
// success
location.reload();
}
}
});
</script>
104 changes: 32 additions & 72 deletions html/layout.html
Original file line number Diff line number Diff line change
@@ -1,83 +1,43 @@
{{ define "header" }}
<!DOCTYPE html>
<html>
<html lang="en">

<head>
<title>Mirage-ECS Dashboard</title>
<style>
body {
padding-top: 60px;
}
</style>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">

<style type="text/css">
.glyphicon-refresh-animate {
-animation: spin .7s infinite linear;
}

@keyframes spin2 {
from {
-webkit-transform: rotate(0deg);
}

to {
-webkit-transform: rotate(360deg);
}
}

@keyframes spin {
from {
transform: scale(1) rotate(0deg);
}

to {
transform: scale(1) rotate(360deg);
}
}
</style>
</head>

<body>

<div class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mirage-ECS Dashboard</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
<script src="https://unpkg.com/htmx.org@1.9.8"></script>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="/">Mirage-ECS</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="row col-1">
<button id="refresh-button" class="btn btn-secondary" hx-get="/list" hx-target="#list-content">refresh</button>
</div>
</div>
</div>
</div>


<div class="container">
<div class="row">
{{ end }}

{{ define "footer" }}
</nav>
<div class="container">
<h1>Current Task List</h1>
<button hx-get="/launcher" hx-target="#launcher" hx-trigger="click" data-bs-toggle="modal" data-bs-target="#launcher"
class="col-2 btn btn-primary">Launch New Task</button>
<div id="list-content" class="row" hx-trigger="load" hx-get="/list"></div>
<div id="launcher" class="modal modal-blur fade" style="display: none" aria-hidden="false" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
<div class="modal-content"></div>
</div>
</div>
<footer>
<p>version: {{ .Version }}</p>
<p>mirage-ecs {{ .Version }}</p>
</footer>
</div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script type="text/javascript">
function terminate(subdomain) {
$("#terminate-subdomain").attr("value", subdomain);
$(".terminate-" + subdomain).html(
'<span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span>' +
' Terminating...')
$("#termination").submit();
}
</script>
</body>

</html>
{{ end }}
15 changes: 5 additions & 10 deletions html/list.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
{{ template "header" }}

<h1>Current Task List</h1>

<p><a href="/launcher" class="btn btn-primary">Launch New Task</a></p>

{{ if .error }}
<p>Error occurred while retreiving information. Detail: {{ .error }} </p>
{{ else }}
Expand Down Expand Up @@ -33,13 +27,14 @@ <h1>Current Task List</h1>
{{ else }}{{$row.Created.Format "2006-01-02 15:04:05 MST"}}
{{end}}</td>
<td class="col-md-2">{{ $row.LastStatus }}</td>
<td class="col-md-2 text-center"><a href="#" class="btn btn-danger" role="button"
onclick="terminate(&quot;{{ $row.SubDomain }}&quot;)" class="terminate-{{ $row.SubDomain }}">Terminate</a>
<td class="col-md-2 text-center">
<button class="btn btn-danger terminate-button" hx-post="/terminate" hx-target="#terminate-subdomain"
hx-trigger="click" hx-confirm="Are you sure you wish to terminate {{ $row.SubDomain }}?"
hx-vals='{"subdomain": "{{ $row.SubDomain }}"}'
onclick="this.addEventListener('htmx:afterRequest', function() { document.querySelector('#refresh-button').click(); });">Terminate</button>
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}

{{ template "footer" . }}
12 changes: 11 additions & 1 deletion webapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"unicode/utf8"

"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/samber/lo"
)

Expand Down Expand Up @@ -56,7 +57,9 @@ func NewWebApi(cfg *Config, runner TaskRunner) *WebApi {

e := echo.New()
e.Use(cfg.AuthMiddleware)
e.GET("/", app.List)
e.Use(middleware.Logger())
e.GET("/", app.Top)
e.GET("/list", app.List)
e.GET("/launcher", app.Launcher)
e.POST("/launch", app.Launch)
e.POST("/terminate", app.Terminate)
Expand All @@ -75,6 +78,10 @@ func NewWebApi(cfg *Config, runner TaskRunner) *WebApi {
return app
}

func (api *WebApi) Top(c echo.Context) error {
return c.Render(http.StatusOK, "layout.html", map[string]interface{}{})
}

func (api *WebApi) List(c echo.Context) error {
info, err := api.runner.List(c.Request().Context(), statusRunning)
value := map[string]interface{}{
Expand Down Expand Up @@ -102,6 +109,9 @@ func (api *WebApi) Launch(c echo.Context) error {
if err != nil {
return c.String(code, err.Error())
}
if c.Request().Header.Get("Hx-Request") == "true" {
return c.String(code, "ok")
}
return c.Redirect(http.StatusSeeOther, "/")
}

Expand Down

0 comments on commit 78ffe41

Please # to comment.