diff --git a/server/app/app.go b/server/app/app.go index 25d9b66a5..749f7dd97 100644 --- a/server/app/app.go +++ b/server/app/app.go @@ -49,6 +49,7 @@ func (app *Router) routes() http.Handler { }) // Serve UI app assets + r.Handle("/", ServeIndex(app.ds)) r.Handle("/*", http.StripPrefix(app.path, http.FileServer(assets.AssetFile()))) return r diff --git a/server/app/serve_index.go b/server/app/serve_index.go new file mode 100644 index 000000000..cd3a5a992 --- /dev/null +++ b/server/app/serve_index.go @@ -0,0 +1,43 @@ +package app + +import ( + "encoding/json" + "html/template" + "io/ioutil" + "net/http" + + "github.com/deluan/navidrome/assets" + "github.com/deluan/navidrome/log" + "github.com/deluan/navidrome/model" +) + +// Injects the `firstTime` config in the `index.html` template +func ServeIndex(ds model.DataStore) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + c, err := ds.User(r.Context()).CountAll() + firstTime := c == 0 && err == nil + + t := template.New("initial state") + fs := assets.AssetFile() + indexHtml, err := fs.Open("index.html") + if err != nil { + log.Error(r, "Could not find `index.html` template", err) + } + indexStr, err := ioutil.ReadAll(indexHtml) + if err != nil { + log.Error(r, "Could not read from `index.html`", err) + } + t, _ = t.Parse(string(indexStr)) + appConfig := map[string]interface{}{ + "firstTime": firstTime, + } + j, _ := json.Marshal(appConfig) + data := map[string]interface{}{ + "AppConfig": string(j), + } + err = t.Execute(w, data) + if err != nil { + log.Error(r, "Could not execute `index.html` template", err) + } + } +} diff --git a/ui/public/index.html b/ui/public/index.html index 12d88a620..43d1a58fb 100644 --- a/ui/public/index.html +++ b/ui/public/index.html @@ -25,6 +25,9 @@ Learn how to configure a non-root public URL by running `npm run build`. --> Navidrome + diff --git a/ui/src/App.js b/ui/src/App.js index 28de38f3d..e3f12e730 100644 --- a/ui/src/App.js +++ b/ui/src/App.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React from 'react' import { Admin, resolveBrowserLocale, Resource } from 'react-admin' import dataProvider from './dataProvider' import authProvider from './authProvider' @@ -19,48 +19,35 @@ const i18nProvider = polyglotI18nProvider( resolveBrowserLocale() ) -const App = () => ( - - {(permissions) => [ - , - , - , - permissions === 'admin' ? : null, - - ]} - -) +const App = () => { + try { + const appConfig = JSON.parse(window.__APP_CONFIG__) -// TODO: This is a complicated way to force a first check for initial setup. A better way would be to send this info -// set in the `window` object in the index.html -const AppWrapper = () => { - const [checked, setChecked] = useState(false) + // This flags to the login process that it should create the first account instead + if (appConfig.firstTime) { + localStorage.setItem('initialAccountCreation', 'true') + } + } catch (e) {} - if (!checked) { - dataProvider - .getOne('keepalive', { id: new Date().getTime() }) - .then(() => setChecked(true)) - .catch((err) => { - authProvider - .checkError(err) - .then(() => { - setChecked(true) - }) - .catch(() => { - setChecked(true) - }) - }) - return null - } - return + return ( + + {(permissions) => [ + , + , + , + permissions === 'admin' ? : null, + + ]} + + ) } -export default AppWrapper +export default App diff --git a/ui/src/authProvider.js b/ui/src/authProvider.js index 3a4e561b4..675faaa33 100644 --- a/ui/src/authProvider.js +++ b/ui/src/authProvider.js @@ -56,11 +56,7 @@ const authProvider = { checkAuth: () => localStorage.getItem('token') ? Promise.resolve() : Promise.reject(), - checkError: (error) => { - const { status, message } = error - if (message === 'no users created') { - localStorage.setItem('initialAccountCreation', 'true') - } + checkError: ({ status }) => { if (status === 401 || status === 403) { removeItems() return Promise.reject()