Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
interfect
funkwhale
Commits
9b4d7165
Verified
Commit
9b4d7165
authored
Apr 14, 2018
by
Eliot Berriot
Browse files
Added federation libraries list, moved scan to a dedicate view
parent
321b9444
Changes
8
Hide whitespace changes
Inline
Side-by-side
api/funkwhale_api/federation/filters.py
View file @
9b4d7165
...
...
@@ -7,6 +7,9 @@ from . import models
class
LibraryFilter
(
django_filters
.
FilterSet
):
approved
=
django_filters
.
BooleanFilter
(
'following__approved'
)
q
=
fields
.
SearchFilter
(
search_fields
=
[
'actor__domain'
,
])
class
Meta
:
model
=
models
.
Library
...
...
front/src/components/Home.vue
View file @
9b4d7165
...
...
@@ -3,7 +3,7 @@
<div
class=
"ui vertical center aligned stripe segment"
>
<div
class=
"ui text container"
>
<h1
class=
"ui huge header"
>
Welcome on Funkwhale
Welcome on Funkwhale
</h1>
<p>
We think listening music should be simple.
</p>
<router-link
class=
"ui icon button"
to=
"/about"
>
...
...
front/src/components/Sidebar.vue
View file @
9b4d7165
...
...
@@ -47,7 +47,7 @@
class=
"item"
:to=
"{path: '/activity'}"
><i
class=
"bell icon"
></i>
Activity
</router-link>
<router-link
class=
"item"
v-if=
"$store.state.auth.availablePermissions['federation.manage']"
:to=
"{path: '/manage/federation'}"
><i
class=
"sitemap icon"
></i>
Federation
</router-link>
:to=
"{path: '/manage/federation
/libraries
'}"
><i
class=
"sitemap icon"
></i>
Federation
</router-link>
</div>
<player></player>
...
...
front/src/components/federation/LibraryCard.vue
View file @
9b4d7165
...
...
@@ -2,33 +2,39 @@
<div
class=
"ui card"
>
<div
class=
"content"
>
<div
class=
"header"
>
{{
libraryData
.
display
_n
ame
}}
{{
display
N
ame
}}
</div>
</div>
<div
class=
"content"
>
<span
class=
"right floated"
v-if=
"libraryData.actor.manuallyApprovesFollowers"
>
<span
class=
"right floated"
v-if=
"following"
>
<i
class=
"check icon"
></i>
Following
</span>
<span
class=
"right floated"
v-else-if=
"manuallyApprovesFollowers"
>
<i
class=
"lock icon"
></i>
Followers only
</span>
<span
class=
"right floated"
v-else
>
<i
class=
"open lock icon"
></i>
Open
</span>
<span>
<i
class=
"music icon"
></i>
{{
libraryData
.
library
.
totalItems
}}
tracks
{{
totalItems
}}
tracks
</span>
</div>
<div
class=
"extra content"
>
<template
v-if=
"
libraryData.local.
awaiting
_a
pproval"
>
<template
v-if=
"awaiting
A
pproval"
>
<i
class=
"clock icon"
></i>
Follow request pending approval
</
template
>
<
template
v-else-if=
"
libraryData.local.following"
>
Pending follow request
<
template
v-else-if=
"
following"
>
<i
class=
"check icon"
></i>
Already following this library
</
template
>
<div
v-
else-
if=
"!library"
v-if=
"!library"
@
click=
"follow"
:disabled=
"isLoading"
:class=
"['ui', 'basic', {loading: isLoading}, 'green', 'button']"
>
<
template
v-if=
"
libraryData.actor.
manuallyApprovesFollowers"
>
<
template
v-if=
"manuallyApprovesFollowers"
>
Send a follow request
</
template
>
<
template
v-else
>
...
...
@@ -49,13 +55,13 @@
import
axios
from
'
axios
'
export
default
{
props
:
[
'
libraryData
'
],
props
:
[
'
libraryData
'
,
'
libraryInstance
'
],
data
()
{
return
{
library
:
this
.
libraryInstance
,
isLoading
:
false
,
data
:
null
,
errors
:
[],
library
:
null
errors
:
[]
}
},
methods
:
{
...
...
@@ -77,6 +83,43 @@ export default {
self
.
errors
=
error
.
backendErrors
})
}
},
computed
:
{
displayName
()
{
if
(
this
.
libraryData
)
{
return
this
.
libraryData
.
display_name
}
else
{
return
`
${
this
.
library
.
actor
.
preferred_username
}
@
${
this
.
library
.
actor
.
domain
}
`
}
},
manuallyApprovesFollowers
()
{
if
(
this
.
libraryData
)
{
return
this
.
libraryData
.
actor
.
manuallyApprovesFollowers
}
else
{
return
this
.
library
.
actor
.
manually_approves_followers
}
},
totalItems
()
{
if
(
this
.
libraryData
)
{
return
this
.
libraryData
.
library
.
totalItems
}
else
{
return
this
.
library
.
tracks_count
}
},
awaitingApproval
()
{
if
(
this
.
libraryData
)
{
return
this
.
libraryData
.
local
.
awaiting_approval
}
else
{
return
this
.
library
.
follow
.
approved
===
null
}
},
following
()
{
if
(
this
.
libraryData
)
{
return
this
.
libraryData
.
local
.
following
}
else
{
return
this
.
library
.
follow
.
approved
}
}
}
}
</
script
>
front/src/router/index.js
View file @
9b4d7165
...
...
@@ -26,8 +26,9 @@ import PlaylistDetail from '@/views/playlists/Detail'
import
PlaylistList
from
'
@/views/playlists/List
'
import
Favorites
from
'
@/components/favorites/List
'
import
FederationBase
from
'
@/views/federation/Base
'
import
Federation
Home
from
'
@/views/federation/
Home
'
import
Federation
Scan
from
'
@/views/federation/
Scan
'
import
FederationLibraryDetail
from
'
@/views/federation/LibraryDetail
'
import
FederationLibraryList
from
'
@/views/federation/LibraryList
'
Vue
.
use
(
Router
)
...
...
@@ -90,15 +91,29 @@ export default new Router({
path
:
'
/manage/federation
'
,
component
:
FederationBase
,
children
:
[
{
path
:
''
,
component
:
FederationHome
},
{
path
:
'
library/:id
'
,
name
:
'
federation.libraries.detail
'
,
component
:
FederationLibraryDetail
,
props
:
true
}
{
path
:
'
scan
'
,
name
:
'
federation.libraries.scan
'
,
component
:
FederationScan
},
{
path
:
'
libraries
'
,
name
:
'
federation.libraries.list
'
,
component
:
FederationLibraryList
,
props
:
(
route
)
=>
({
defaultOrdering
:
route
.
query
.
ordering
,
defaultQuery
:
route
.
query
.
query
,
defaultPaginateBy
:
route
.
query
.
paginateBy
,
defaultPage
:
route
.
query
.
page
})
},
{
path
:
'
libraries/:id
'
,
name
:
'
federation.libraries.detail
'
,
component
:
FederationLibraryDetail
,
props
:
true
}
]
},
{
path
:
'
/library
'
,
component
:
Library
,
children
:
[
{
path
:
''
,
component
:
LibraryHome
},
{
path
:
'
scan
'
,
component
:
LibraryHome
},
{
path
:
'
artists/
'
,
name
:
'
library.artists.browse
'
,
...
...
front/src/views/federation/Base.vue
View file @
9b4d7165
<
template
>
<div
class=
"main pusher"
v-title=
"'Federation'"
>
<div
class=
"ui secondary pointing menu"
>
<router-link
class=
"ui item"
:to=
"
{name: 'federation.libraries.list'}">Libraries
</router-link>
</div>
<router-view
:key=
"$route.fullPath"
></router-view>
</div>
</
template
>
<
style
lang=
"scss"
>
@import
'../../style/vendor/media'
;
.main.pusher
>
.ui.secondary.menu
{
@include
media
(
">tablet"
)
{
margin
:
0
2
.5rem
;
}
.item
{
padding-top
:
1
.5em
;
padding-bottom
:
1
.5em
;
}
}
</
style
>
front/src/views/federation/LibraryList.vue
0 → 100644
View file @
9b4d7165
<
template
>
<div
v-title=
"'Artists'"
>
<div
class=
"ui vertical stripe segment"
>
<h2
class=
"ui header"
>
Browsing libraries
</h2>
<router-link
class=
"ui basic green button"
:to=
"
{name: 'federation.libraries.scan'}">
<i
class=
"plus icon"
></i>
Add a new library
</router-link>
<div
class=
"ui hidden divider"
></div>
<div
:class=
"['ui',
{'loading': isLoading}, 'form']">
<div
class=
"fields"
>
<div
class=
"field"
>
<label>
Search
</label>
<input
type=
"text"
v-model=
"query"
placeholder=
"Enter an library domain name..."
/>
</div>
<div
class=
"field"
>
<label>
Ordering
</label>
<select
class=
"ui dropdown"
v-model=
"ordering"
>
<option
v-for=
"option in orderingOptions"
:value=
"option[0]"
>
{{
option
[
1
]
}}
</option>
</select>
</div>
<div
class=
"field"
>
<label>
Ordering direction
</label>
<select
class=
"ui dropdown"
v-model=
"orderingDirection"
>
<option
value=
""
>
Ascending
</option>
<option
value=
"-"
>
Descending
</option>
</select>
</div>
<div
class=
"field"
>
<label>
Results per page
</label>
<select
class=
"ui dropdown"
v-model=
"paginateBy"
>
<option
:value=
"parseInt(12)"
>
12
</option>
<option
:value=
"parseInt(25)"
>
25
</option>
<option
:value=
"parseInt(50)"
>
50
</option>
</select>
</div>
</div>
</div>
<div
class=
"ui hidden divider"
></div>
<div
v-if=
"result"
v-masonry
transition-duration=
"0"
item-selector=
".column"
percent-position=
"true"
stagger=
"0"
class=
"ui stackable three column doubling grid"
>
<div
v-masonry-tile
v-if=
"result.results.length > 0"
v-for=
"library in result.results"
:key=
"library.id"
class=
"column"
>
<library-card
class=
"fluid"
:library-instance=
"library"
></library-card>
</div>
</div>
<div
class=
"ui center aligned basic segment"
>
<pagination
v-if=
"result && result.results.length > 0"
@
page-changed=
"selectPage"
:current=
"page"
:paginate-by=
"paginateBy"
:total=
"result.count"
></pagination>
</div>
</div>
</div>
</
template
>
<
script
>
import
axios
from
'
axios
'
import
_
from
'
lodash
'
import
$
from
'
jquery
'
import
logger
from
'
@/logging
'
import
OrderingMixin
from
'
@/components/mixins/Ordering
'
import
PaginationMixin
from
'
@/components/mixins/Pagination
'
import
LibraryCard
from
'
@/components/federation/LibraryCard
'
import
Pagination
from
'
@/components/Pagination
'
const
FETCH_URL
=
'
federation/libraries/
'
export
default
{
mixins
:
[
OrderingMixin
,
PaginationMixin
],
props
:
{
defaultQuery
:
{
type
:
String
,
required
:
false
,
default
:
''
}
},
components
:
{
LibraryCard
,
Pagination
},
data
()
{
let
defaultOrdering
=
this
.
getOrderingFromString
(
this
.
defaultOrdering
||
'
-creation_date
'
)
return
{
isLoading
:
true
,
result
:
null
,
page
:
parseInt
(
this
.
defaultPage
),
query
:
this
.
defaultQuery
,
paginateBy
:
parseInt
(
this
.
defaultPaginateBy
||
50
),
orderingDirection
:
defaultOrdering
.
direction
,
ordering
:
defaultOrdering
.
field
,
orderingOptions
:
[
[
'
creation_date
'
,
'
Creation date
'
],
[
'
tracks_count
'
,
'
Available tracks
'
]
]
}
},
created
()
{
this
.
fetchData
()
},
mounted
()
{
$
(
'
.ui.dropdown
'
).
dropdown
()
},
methods
:
{
updateQueryString
:
_
.
debounce
(
function
()
{
this
.
$router
.
replace
({
query
:
{
query
:
this
.
query
,
page
:
this
.
page
,
paginateBy
:
this
.
paginateBy
,
ordering
:
this
.
getOrderingAsString
()
}
})
},
500
),
fetchData
:
_
.
debounce
(
function
()
{
var
self
=
this
this
.
isLoading
=
true
let
url
=
FETCH_URL
let
params
=
{
page
:
this
.
page
,
q
:
this
.
query
,
ordering
:
this
.
getOrderingAsString
()
}
logger
.
default
.
debug
(
'
Fetching libraries
'
)
axios
.
get
(
url
,
{
params
:
params
}).
then
((
response
)
=>
{
self
.
result
=
response
.
data
self
.
isLoading
=
false
})
},
500
),
selectPage
:
function
(
page
)
{
this
.
page
=
page
}
},
watch
:
{
page
()
{
this
.
updateQueryString
()
this
.
fetchData
()
},
ordering
()
{
this
.
updateQueryString
()
this
.
fetchData
()
},
orderingDirection
()
{
this
.
updateQueryString
()
this
.
fetchData
()
},
query
()
{
this
.
updateQueryString
()
this
.
fetchData
()
}
}
}
</
script
>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<
style
scoped
>
</
style
>
front/src/views/federation/
Home
.vue
→
front/src/views/federation/
Scan
.vue
View file @
9b4d7165
<
template
>
<div>
<div
class=
"ui vertical stripe segment"
>
<h1
class=
"ui header"
>
Manage federation
</h1>
<library-form
@
scanned=
"updateLibraryData"
></library-form>
<library-card
v-if=
"libraryData"
:library-data=
"libraryData"
></library-card>
</div>
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment