Compare commits

...

10 Commits

Author SHA1 Message Date
Amir Raminfar b96785f2be Adds title for pages 2018-11-25 16:14:55 -08:00
Amir Raminfar dd6f4b1e31 1.2.7 2018-11-25 12:24:15 -08:00
Amir Raminfar 651291ecad Removes hostname from title 2018-11-25 12:23:29 -08:00
Amir Raminfar a5bcec68cb 1.2.6 2018-11-25 12:14:12 -08:00
Amir Raminfar 77d6a22122 Disables source maps 2018-11-25 12:14:00 -08:00
Amir Raminfar 40f97073e8 1.2.5 2018-11-25 12:10:55 -08:00
Amir Raminfar 75339ffba1 Docker hostname added 2018-11-25 12:10:46 -08:00
Amir Raminfar 2fdfba5a42 Updates packages in node 2018-11-25 12:06:49 -08:00
Amir Raminfar 5987330cdc 1.2.4 2018-11-24 17:48:24 -08:00
Amir Raminfar 14c7c21f9f Fixes bug on ipad 2018-11-24 17:48:18 -08:00
6 changed files with 156 additions and 131 deletions
+6 -1
View File
@@ -14,7 +14,7 @@
<ul class="menu-list is-hidden-mobile" :class="{ 'is-active': showNav }">
<li v-for="item in containers">
<router-link
:to="{ name: 'container', params: { id: item.Id } }"
:to="{ name: 'container', params: { id: item.Id, name: item.Names[0] } }"
active-class="is-active"
class="tooltip is-tooltip-right is-tooltip-info"
:data-tooltip="item.Names[0]"
@@ -25,6 +25,7 @@
</ul>
</aside>
<div class="column is-offset-2"><router-view></router-view></div>
<vue-headful :title="title" />
</div>
</template>
@@ -33,12 +34,14 @@ export default {
name: "App",
data() {
return {
title: "Dozzle",
containers: [],
showNav: false
};
},
async created() {
this.containers = await (await fetch(`${BASE_PATH}/api/containers.json`)).json();
this.title = `${this.containers.length} containers - Dozzle`;
}
};
</script>
@@ -61,6 +64,8 @@ aside {
& {
position: sticky;
top: 0;
left: 0;
right: 0;
background: #222;
}
+2
View File
@@ -1,10 +1,12 @@
import Vue from "vue";
import VueRouter from "vue-router";
import vueHeadful from "vue-headful";
import App from "./App.vue";
import Container from "./pages/Container.vue";
import Index from "./pages/Index.vue";
Vue.use(VueRouter);
Vue.component("vue-headful", vueHeadful);
const routes = [
{
+6 -3
View File
@@ -6,6 +6,7 @@
</li>
</ul>
<scrollbar-notification :messages="messages"></scrollbar-notification>
<vue-headful :title="title" />
</div>
</template>
@@ -29,14 +30,15 @@ const parseMessage = data => {
};
export default {
props: ["id"],
props: ["id", "name"],
name: "Container",
components: {
ScrollbarNotification
},
data() {
return {
messages: []
messages: [],
title: ""
};
},
created() {
@@ -61,7 +63,7 @@ export default {
this.messages = [];
}
const protocol = SSL_ENABLED ? "wss" : "ws";
ws = new WebSocket(`${protocol}://${window.location.host}${BASE_PATH}/api/logs?id=${this.id}`);
ws = new WebSocket(`${protocol}://${window.location.host}${BASE_PATH}/api/logs?id=${id}`);
ws.onopen = e => console.log("Connection opened.");
ws.onclose = e => console.log("Connection closed.");
ws.onerror = e => console.error("Connection error: " + e.data);
@@ -69,6 +71,7 @@ export default {
const message = parseMessage(e.data);
this.messages.push(message);
};
this.title = `${this.name} - Dozzle`;
}
}
};
+110 -109
View File
@@ -1,143 +1,144 @@
package main
import (
"context"
"encoding/binary"
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"
"strings"
"context"
"encoding/binary"
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/gobuffalo/packr"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
flag "github.com/spf13/pflag"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/gobuffalo/packr"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
flag "github.com/spf13/pflag"
)
var (
cli *client.Client
addr = ""
ssl = false
base = "/"
upgrader = websocket.Upgrader{}
version = "dev"
commit = "none"
date = "unknown"
cli *client.Client
addr = ""
ssl = false
base = "/"
upgrader = websocket.Upgrader{}
version = "dev"
commit = "none"
date = "unknown"
)
func init() {
flag.StringVar(&addr, "addr", ":8080", "http service address")
flag.StringVar(&base, "base", "/", "base address of the application to mount")
flag.BoolVarP(&ssl, "ssl", "s", false, "Uses websockets over ssl if enabled")
flag.StringVar(&addr, "addr", ":8080", "http service address")
flag.StringVar(&base, "base", "/", "base address of the application to mount")
flag.BoolVarP(&ssl, "ssl", "s", false, "Uses websockets over ssl if enabled")
var err error
cli, err = client.NewClientWithOpts(client.FromEnv)
if err != nil {
log.Fatal(err)
}
flag.Parse()
var err error
cli, err = client.NewClientWithOpts(client.FromEnv)
if err != nil {
log.Fatal(err)
}
flag.Parse()
}
func main() {
r := mux.NewRouter()
r := mux.NewRouter()
if base != "/" {
r.HandleFunc(base, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
http.Redirect(w, req, base+"/", http.StatusMovedPermanently)
}))
}
if base != "/" {
r.HandleFunc(base, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
http.Redirect(w, req, base+"/", http.StatusMovedPermanently)
}))
}
s := r.PathPrefix(base).Subrouter()
box := packr.NewBox("./static")
s := r.PathPrefix(base).Subrouter()
box := packr.NewBox("./static")
s.HandleFunc("/api/containers.json", listContainers)
s.HandleFunc("/api/logs", logs)
s.HandleFunc("/version", versionHandler)
s.PathPrefix("/").Handler(http.StripPrefix(base, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
fileServer := http.FileServer(box)
if box.Has(req.URL.Path) && req.URL.Path != "" && req.URL.Path != "/" {
fileServer.ServeHTTP(w, req)
} else {
handleIndex(box, w)
}
})))
s.HandleFunc("/api/containers.json", listContainers)
s.HandleFunc("/api/logs", logs)
s.HandleFunc("/version", versionHandler)
s.PathPrefix("/").Handler(http.StripPrefix(base, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
fileServer := http.FileServer(box)
if box.Has(req.URL.Path) && req.URL.Path != "" && req.URL.Path != "/" {
fileServer.ServeHTTP(w, req)
} else {
handleIndex(box, w)
}
})))
log.Fatal(http.ListenAndServe(addr, r))
log.Fatal(http.ListenAndServe(addr, r))
}
func versionHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, version)
fmt.Fprintln(w, commit)
fmt.Fprintln(w, date)
fmt.Fprintln(w, version)
fmt.Fprintln(w, commit)
fmt.Fprintln(w, date)
}
func listContainers(w http.ResponseWriter, r *http.Request) {
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
log.Fatal(err)
}
json.NewEncoder(w).Encode(containers)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
log.Fatal(err)
}
json.NewEncoder(w).Encode(containers)
}
func handleIndex(box packr.Box, w http.ResponseWriter) {
text, _ := box.FindString("index.html")
text = strings.Replace(text, "__BASE__", "{{ .Base }}", -1)
tmpl, err := template.New("index.html").Parse(text)
if err != nil {
panic(err)
}
text, _ := box.FindString("index.html")
text = strings.Replace(text, "__BASE__", "{{ .Base }}", -1)
tmpl, err := template.New("index.html").Parse(text)
if err != nil {
panic(err)
}
path := ""
if base != "/" {
path = base
}
data := struct {
Base string
SSL bool
}{path, ssl}
err = tmpl.Execute(w, data)
if err != nil {
panic(err)
}
path := ""
if base != "/" {
path = base
}
data := struct {
Base string
SSL bool
}{path, ssl}
err = tmpl.Execute(w, data)
if err != nil {
panic(err)
}
}
func logs(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatal(err)
return
}
defer c.Close()
id := r.URL.Query().Get("id")
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatal(err)
return
}
defer c.Close()
options := types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true, Tail: "300", Timestamps: true}
reader, err := cli.ContainerLogs(context.Background(), id, options)
defer reader.Close()
if err != nil {
log.Fatal(err)
}
options := types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true, Tail: "300", Timestamps: true}
reader, err := cli.ContainerLogs(context.Background(), id, options)
defer reader.Close()
if err != nil {
log.Fatal(err)
}
hdr := make([]byte, 8)
content := make([]byte, 1024, 1024*1024)
for {
_, err := reader.Read(hdr)
if err != nil {
log.Panicln(err)
}
count := binary.BigEndian.Uint32(hdr[4:])
n, err := reader.Read(content[:count])
if err != nil {
log.Println(err)
break
}
err = c.WriteMessage(websocket.TextMessage, content[:n])
if err != nil {
log.Println(err)
break
}
}
hdr := make([]byte, 8)
content := make([]byte, 1024, 1024*1024)
for {
_, err := reader.Read(hdr)
if err != nil {
log.Panicln(err)
}
count := binary.BigEndian.Uint32(hdr[4:])
n, err := reader.Read(content[:count])
if err != nil {
log.Println(err)
break
}
err = c.WriteMessage(websocket.TextMessage, content[:n])
if err != nil {
log.Println(err)
break
}
}
}
+26 -13
View File
@@ -1,6 +1,6 @@
{
"name": "dozzle",
"version": "1.2.3",
"version": "1.2.7",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1264,7 +1264,7 @@
},
"ansi-escapes": {
"version": "3.1.0",
"resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
"integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==",
"dev": true
},
@@ -4001,7 +4001,7 @@
},
"globby": {
"version": "6.1.0",
"resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
"resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
"integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
"dev": true,
"requires": {
@@ -4130,6 +4130,11 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true
},
"headful": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/headful/-/headful-1.0.3.tgz",
"integrity": "sha512-vF9Vfddn1QWmziliht2mji6ayI78+hUuSC+Kt0GEqLw/51zWgi1KF7oLtIQf3nlkg8sQQOlznkkIaF4W9lIt9w=="
},
"hex-color-regex": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
@@ -4648,9 +4653,9 @@
"dev": true
},
"husky": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/husky/-/husky-1.1.4.tgz",
"integrity": "sha512-cZjGpS7qsaBSo3fOMUuR7erQloX3l5XzL1v/RkIqU6zrQImDdU70z5Re9fGDp7+kbYlM2EtS4aYMlahBeiCUGw==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/husky/-/husky-1.2.0.tgz",
"integrity": "sha512-/ib3+iycykXC0tYIxsyqierikVa9DA2DrT32UEirqNEFVqOj1bFMTgP3jAz8HM7FgC/C8pc/BTUa9MV2GEkZaA==",
"dev": true,
"requires": {
"cosmiconfig": "^5.0.6",
@@ -5195,15 +5200,15 @@
}
},
"lint-staged": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.0.5.tgz",
"integrity": "sha512-QI2D6lw2teArlr2fmrrCIqHxef7mK2lKjz9e+aZSzFlk5rsy10rg97p3wA9H/vIFR3Fvn34fAgUktD/k896S2A==",
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.0.tgz",
"integrity": "sha512-yfSkyJy7EuVsaoxtUSEhrD81spdJOe/gMTGea3XaV7HyoRhTb9Gdlp6/JppRZERvKSEYXP9bjcmq6CA5oL2lYQ==",
"dev": true,
"requires": {
"@iamstarkov/listr-update-renderer": "0.4.1",
"chalk": "^2.3.1",
"commander": "^2.14.1",
"cosmiconfig": "^5.0.2",
"cosmiconfig": "5.0.6",
"debug": "^3.1.0",
"dedent": "^0.7.0",
"del": "^3.0.0",
@@ -9126,6 +9131,14 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-2.5.17.tgz",
"integrity": "sha512-mFbcWoDIJi0w0Za4emyLiW72Jae0yjANHbCVquMKijcavBGypqlF7zHRgMa5k4sesdv7hv2rB4JPdZfR+TPfhQ=="
},
"vue-headful": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/vue-headful/-/vue-headful-2.0.1.tgz",
"integrity": "sha512-h2G/jXCi2hAx6O3gwWN8uTj1eQlSKNHgvkCVZcokZneGczWCRghAUCFYrOvZQM+F+SyFB3YXqoI62rE0Sc8QsA==",
"requires": {
"headful": "^1.0.3"
}
},
"vue-hot-reload-api": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.1.tgz",
@@ -9133,9 +9146,9 @@
"dev": true
},
"vue-router": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.1.tgz",
"integrity": "sha512-vLLoY452L+JBpALMP5UHum9+7nzR9PeIBCghU9ZtJ1eWm6ieUI8Zb/DI3MYxH32bxkjzYV1LRjNv4qr8d+uX/w=="
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.2.tgz",
"integrity": "sha512-opKtsxjp9eOcFWdp6xLQPLmRGgfM932Tl56U9chYTnoWqKxQ8M20N7AkdEbM5beUh6wICoFGYugAX9vQjyJLFg=="
},
"vue-template-compiler": {
"version": "2.5.17",
+6 -5
View File
@@ -1,13 +1,13 @@
{
"name": "dozzle",
"version": "1.2.3",
"version": "1.2.7",
"description": "",
"main": "index.js",
"scripts": {
"start": "concurrently 'go run main.go' 'npm run watch-assets'",
"watch-assets": "parcel watch --public-url '__BASE__' assets/index.html -d static",
"prebuild": "npm run clean",
"build": "parcel build --public-url '__BASE__' assets/index.html -d static",
"build": "parcel build --no-source-maps --public-url '__BASE__' assets/index.html -d static",
"clean": "rm -rf static",
"release": "goreleaser --rm-dist"
},
@@ -26,15 +26,16 @@
"bulma-tooltip": "^2.0.2",
"date-fns": "^2.0.0-alpha.25",
"vue": "^2.5.17",
"vue-router": "^3.0.1"
"vue-headful": "^2.0.1",
"vue-router": "^3.0.2"
},
"devDependencies": {
"@babel/core": "^7.1.6",
"@babel/plugin-transform-runtime": "^7.1.0",
"@vue/component-compiler-utils": "^2.3.0",
"concurrently": "^4.1.0",
"husky": "^1.1.4",
"lint-staged": "^8.0.5",
"husky": "^1.2.0",
"lint-staged": "^8.1.0",
"parcel-bundler": "^1.10.3",
"prettier": "^1.15.2",
"sass": "^1.15.1",