From 292e24978da990763f37ecd21d0d2b58dc384877 Mon Sep 17 00:00:00 2001 From: Gabriel Simmer Date: Sun, 22 Mar 2020 00:18:19 +0000 Subject: [PATCH] Implement new frontend, "/" at end of provider. Started work on a new basic frontend, with some magic code from @tomhodgins (Tom Hodgins) for templating and processing data, which was the primary purpose for considering a full-fledged JavaScript framework. Fairly simple right now, with minimal "bling", and seems "functional enough". Might need to consider options for using less or no JS down the line if there is demand. As part of this frontend, actually implemented route logic for fetching a sorted list of providers (might be worth investigating whether storing this final result in memory is worth the performance to memory trade-off). Also fixed a bug where adding "/" to the end of a provider name without a file path would result in a 404. This was addressed with some Regex filtering on the path that should be able to handle that matching. --- .gitignore | 1 - assets/web/css/styles.css | 48 ++++++++++++++++++++++ assets/web/index.html | 19 +++++++++ assets/web/javascript/app.js | 80 ++++++++++++++++++++++++++++++++++++ router/filerouter.go | 13 ++++++ router/router.go | 9 ++-- 6 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 assets/web/css/styles.css create mode 100644 assets/web/index.html create mode 100644 assets/web/javascript/app.js diff --git a/.gitignore b/.gitignore index c2466e6..7be6860 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,3 @@ nas *.db .lock -assets/web/* \ No newline at end of file diff --git a/assets/web/css/styles.css b/assets/web/css/styles.css new file mode 100644 index 0000000..c32c23d --- /dev/null +++ b/assets/web/css/styles.css @@ -0,0 +1,48 @@ +* { + font-family: sans-serif; +} + +body { + +} + +.grid-lg, .grid-sm { + display: grid; + grid-template-columns: repeat(5, 1fr); + grid-template-rows: repeat(5, 2fr); + grid-column-gap: 5px; + grid-row-gap: 5px; +} + +.grid-lg a { + display: flex; + padding: 10vh; + justify-content: center; + background-color: black; + font-size: 32px; + font-weight: bold; + text-decoration: none; + transition: background-color 0.5s; +} + +.grid-sm a { + display: flex; + padding: 2vh; + justify-content: center; + background-color: black; + font-size: 24px; + font-weight: bold; + text-decoration: none; + transition: background-color 0.5s; +} + +.grid-lg a:visited, .grid-lg a, +.grid-sm a:visited, .grid-sm a { + color: white; +} +.grid-lg a:hover, +.grid-sm a:hover { + color: white; + background-color: darkgray; + transition: background-color 0.5s; +} \ No newline at end of file diff --git a/assets/web/index.html b/assets/web/index.html new file mode 100644 index 0000000..ba7a49f --- /dev/null +++ b/assets/web/index.html @@ -0,0 +1,19 @@ + + + + + + + NAS + + + +

NAS

+ +
+
+ + + + \ No newline at end of file diff --git a/assets/web/javascript/app.js b/assets/web/javascript/app.js new file mode 100644 index 0000000..483a50f --- /dev/null +++ b/assets/web/javascript/app.js @@ -0,0 +1,80 @@ +// Register our router, and fire it off initially in case user is being linked a dir. +window.addEventListener("hashchange", router, false); +router() + +function getFileListing(provider, path = "") { + fetch(`/api/files/${provider}${path}`) + .then((response) => { + return response.json() + }) + .then((data) => { + let files = data["Files"] + html` +
+ ${files.map(file => + ` + ${file.Name}${file.IsDirectory ? '/' : ''} + + ` + ).join('')} +
+ ` + }) +} + +function getProviders() { + fetch(`/api/providers`) + .then((response) => { + return response.json() + }) + .then((data) => { + let providers = data + html` +
+ ${providers.map(provider => + ` + ${provider} + + ` + ).join('')} +
+ ` + }) +} + +function router(event = null) { + let hash = location.hash.replace("#", "") + // If hash is empty, "redirect" to index. + if (hash === "") { + getProviders() + return + } + + let path = hash.split("/") + let provider = path.shift() + console.log(path, provider) + getFileListing(provider, "/" + path) +} + +// Tagged template function for parsing a string of text as HTML objects +// <3 @innovati for this brilliance. +function html(strings, ...things) { + // Our "body", where we'll render stuff. + const body = document.getElementById("main") + let x = document.createRange().createContextualFragment( + strings.reduce( + (markup, string, index) => { + markup += string + + if (things[index]) { + markup += things[index] + } + + return markup + }, + '' + ) + ) + body.innerHTML = "" + body.append(x) +} \ No newline at end of file diff --git a/router/filerouter.go b/router/filerouter.go index c385332..8726377 100644 --- a/router/filerouter.go +++ b/router/filerouter.go @@ -6,6 +6,8 @@ import ( "github.com/gmemstr/nas/files" "github.com/gorilla/mux" "net/http" + "sort" + "strings" ) func HandleProvider() common.Handler { @@ -14,6 +16,7 @@ func HandleProvider() common.Handler { vars := mux.Vars(r) if r.Method == "GET" { providerCodename := vars["provider"] + providerCodename = strings.Replace(providerCodename, "/", "", -1) provider := *files.Providers[providerCodename] fileList := provider.GetDirectory("") @@ -44,6 +47,16 @@ func HandleProvider() common.Handler { func ListProviders() common.Handler { return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError { + var providers []string + for v, _ := range files.ProviderConfig { + providers = append(providers, v) + } + sort.Strings(providers) + data, err := json.Marshal(providers) + if err != nil { + return nil + } + w.Write(data) return nil } } diff --git a/router/router.go b/router/router.go index 4955a50..10ee68f 100644 --- a/router/router.go +++ b/router/router.go @@ -35,11 +35,12 @@ func Init() *mux.Router { r := mux.NewRouter() // "Static" paths - r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("assets/web/static")))) + r.PathPrefix("/javascript/").Handler(http.StripPrefix("/javascript/", http.FileServer(http.Dir("assets/web/javascript")))) + r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", http.FileServer(http.Dir("assets/web/css")))) // Paths that require specific handlers r.Handle("/", Handle( - auth.RequireAuthorization(1), + //auth.RequireAuthorization(1), rootHandler(), )).Methods("GET") @@ -48,11 +49,11 @@ func Init() *mux.Router { )).Methods("POST", "GET") r.Handle("/api/providers", Handle( - auth.RequireAuthorization(1), + //auth.RequireAuthorization(1), ListProviders(), )).Methods("GET") - r.Handle(`/api/files/{provider}`, Handle( + r.Handle(`/api/files/{provider:[a-zA-Z0-9]+\/*}`, Handle( //auth.RequireAuthorization(1), HandleProvider(), )).Methods("GET")