From 7dc3f49c1c5563bc7d4d4a755815317632b45ca6 Mon Sep 17 00:00:00 2001
From: Deluan <deluan@deluan.com>
Date: Wed, 22 Jan 2020 13:02:19 -0500
Subject: [PATCH] Initial support for artist browsing from UI. Also add linking
 between resources

---
 persistence/artist_repository.go |  6 ++---
 server/app/app.go                |  9 +++++---
 ui/src/App.js                    |  2 ++
 ui/src/album/AlbumList.js        |  5 ++++-
 ui/src/artist/ArtistList.js      | 38 ++++++++++++++++++++++++++++++++
 ui/src/artist/index.js           |  7 ++++++
 6 files changed, 60 insertions(+), 7 deletions(-)
 create mode 100644 ui/src/artist/ArtistList.js
 create mode 100644 ui/src/artist/index.js

diff --git a/persistence/artist_repository.go b/persistence/artist_repository.go
index 08804b47a..689ceb551 100644
--- a/persistence/artist_repository.go
+++ b/persistence/artist_repository.go
@@ -15,9 +15,9 @@ import (
 )
 
 type artist struct {
-	ID         string `orm:"pk;column(id)"`
-	Name       string `orm:"index"`
-	AlbumCount int    `orm:"column(album_count)"`
+	ID         string `json:"id"         orm:"pk;column(id)"`
+	Name       string `json:"name"       orm:"index"`
+	AlbumCount int    `json:"albumCount" orm:"column(album_count)"`
 }
 
 type artistRepository struct {
diff --git a/server/app/app.go b/server/app/app.go
index 3c412bace..f028fd757 100644
--- a/server/app/app.go
+++ b/server/app/app.go
@@ -6,6 +6,7 @@ import (
 	"net/url"
 	"strings"
 
+	"github.com/cloudsonic/sonic-server/conf"
 	"github.com/cloudsonic/sonic-server/model"
 	"github.com/cloudsonic/sonic-server/server"
 	"github.com/deluan/rest"
@@ -47,12 +48,14 @@ func (app *Router) routes() http.Handler {
 	r.Post("/login", Login(app.ds))
 
 	r.Route("/api", func(r chi.Router) {
-		// Add User resource
-		r.Use(jwtauth.Verifier(TokenAuth))
-		r.Use(Authenticator)
+		if !conf.Sonic.DevDisableAuthentication {
+			r.Use(jwtauth.Verifier(TokenAuth))
+			r.Use(Authenticator)
+		}
 		app.R(r, "/user", model.User{})
 		app.R(r, "/song", model.MediaFile{})
 		app.R(r, "/album", model.Album{})
+		app.R(r, "/artist", model.Artist{})
 	})
 	return r
 }
diff --git a/ui/src/App.js b/ui/src/App.js
index 9a248980f..9504f1cbb 100644
--- a/ui/src/App.js
+++ b/ui/src/App.js
@@ -7,6 +7,7 @@ import { Login, Layout } from './layout'
 import user from './user'
 import song from './song'
 import album from './album'
+import artist from './artist'
 
 const App = () => (
   <Admin
@@ -17,6 +18,7 @@ const App = () => (
   >
     <Resource name="song" {...song} options={{ subMenu: 'library' }} />
     <Resource name="album" {...album} options={{ subMenu: 'library' }} />
+    <Resource name="artist" {...artist} options={{ subMenu: 'library' }} />
     <Resource name="user" {...user} />
   </Admin>
 )
diff --git a/ui/src/album/AlbumList.js b/ui/src/album/AlbumList.js
index 03557bde7..c88a047c6 100644
--- a/ui/src/album/AlbumList.js
+++ b/ui/src/album/AlbumList.js
@@ -34,6 +34,9 @@ const AlbumDetails = (props) => {
   )
 }
 
+const albumRowClick = (id, basePath, record) =>
+  `/song?filter={"album_id":"${record.id}"}&order=ASC&sort=trackNumber`
+
 const AlbumList = (props) => (
   <List
     {...props}
@@ -44,7 +47,7 @@ const AlbumList = (props) => (
     filters={<AlbumFilter />}
     perPage={15}
   >
-    <Datagrid expand={<AlbumDetails />}>
+    <Datagrid expand={<AlbumDetails />} rowClick={albumRowClick}>
       <TextField source="name" />
       <TextField source="artist" />
       <NumberField source="songCount" />
diff --git a/ui/src/artist/ArtistList.js b/ui/src/artist/ArtistList.js
new file mode 100644
index 000000000..7a345779f
--- /dev/null
+++ b/ui/src/artist/ArtistList.js
@@ -0,0 +1,38 @@
+import React from 'react'
+import {
+  Datagrid,
+  Filter,
+  List,
+  NumberField,
+  SearchInput,
+  TextField
+} from 'react-admin'
+import { Title } from '../common'
+
+const ArtistFilter = (props) => (
+  <Filter {...props}>
+    <SearchInput source="name" alwaysOn />
+  </Filter>
+)
+
+const artistRowClick = (id, basePath, record) =>
+  `/album?filter={"artist_id":"${record.id}"}&order=ASC&sort=year`
+
+const ArtistList = (props) => (
+  <List
+    {...props}
+    title={<Title subTitle={'Artists'} />}
+    sort={{ field: 'name', order: 'ASC' }}
+    exporter={false}
+    bulkActionButtons={false}
+    filters={<ArtistFilter />}
+    perPage={15}
+  >
+    <Datagrid rowClick={artistRowClick}>
+      <TextField source="name" />
+      <NumberField source="albumCount" />
+    </Datagrid>
+  </List>
+)
+
+export default ArtistList
diff --git a/ui/src/artist/index.js b/ui/src/artist/index.js
new file mode 100644
index 000000000..cce746461
--- /dev/null
+++ b/ui/src/artist/index.js
@@ -0,0 +1,7 @@
+import MicIcon from '@material-ui/icons/Mic'
+import ArtistList from './ArtistList'
+
+export default {
+  list: ArtistList,
+  icon: MicIcon
+}