Docs: update for new UI, schema, debugging and federation

Co-Authored-By: ArneBo <arne@ecobasa.org>
Co-Authored-By: Flupsi <upsiflu@gmail.com>
Co-Authored-By: jon r <jon@allmende.io>
This commit is contained in:
jon r 2025-04-18 11:24:50 +02:00
parent a9582fc1e9
commit cbd0ba2872
7 changed files with 112 additions and 651 deletions

View File

@ -129,8 +129,13 @@ def test_downgrade_not_superuser_skips_email(factories, mocker):
mocked_notify.assert_not_called()
```
<!-- prettier-ignore-start -->
(runtests)=
## Run tests
<!-- prettier-ignore-end -->
You can run all tests in the pytest suite with the following command:
```sh

View File

@ -47,8 +47,8 @@ const labels = computed(() => ({
:::{tab-item} Template
```html
<h2>{{ $t('components.About.header.funkwhale') }}</h2>
<button>{{ $t('components.About.button.cancel') }}</button>
<h2>{{ t('components.About.header.funkwhale') }}</h2>
<button>{{ t('components.About.button.cancel') }}</button>
```
:::
@ -84,11 +84,11 @@ Some strings change depending on whether they are plural or not. You can create
v-if="object.artist?.content_category === 'podcast'"
class="meta ellipsis"
>
{{ $t('components.audio.ChannelCard.meta.episodes', {episode_count:
{{ t('components.audio.ChannelCard.meta.episodes', {episode_count:
object.artist.tracks_count}) }}
</span>
<span v-else>
{{ $t('components.audio.ChannelCard.meta.tracks', {tracks_count:
{{ t('components.audio.ChannelCard.meta.tracks', {tracks_count:
object.artist?.tracks_count}) }}
</span>
<tags-list

View File

@ -2,25 +2,72 @@
The Funkwhale frontend is a {abbr}`SPA (Single Page Application)` written in [Typescript](https://typescriptlang.org) and [Vue.js](https://vuejs.org).
## Troubleshooting
### Network errors (405 and 404) in the console
If you are using Google Chrome, you may have to disable the network cache:
- Go to the Dev Tools
- Select the Network tab
- In the toolbar under the Network tab, activate the checkmark "Disable Cache"
### Edits don't appear when I check them in the browser
Reload the page with `Ctrl+Shift+R` (Mac: `Cmd+Shift+R`)
Make sure you have no add-ons in your browser that mess with the DOM. The best way to check is to open a private window/tab with `Ctrl/Cmd+Shift+P` (Firefox)
## Styles
We currently use [Fomantic UI](https://fomantic-ui.com) as our UI framework. We customize this with our own SCSS files located in `front/src/styles/_main.scss`.
<--! TODO: Mermaid diagrams -->
We apply changes to the Fomantic CSS files before we import them:
### UI styles
1. We replace hardcoded color values with CSS variables to make themin easier. For example: `color: orange` is replaced by `color: var(--vibrant-color)`
2. We remove unused values from the CSS files to keep the size down
```mermaid
graph TD
/node_modules/bootstrap-icons/font/bootstrap-icons.css --> src/styles/font.scss
src/styles/base/generic.scss --> src/styles/base/index.scss
src/styles/base/index.scss --> src/styles/funkwhale.scss
src/styles/font.scss --> src/styles/funkwhale.scss
src/styles/colors.scss --> src/styles/funkwhale.scss
src/styles/funkwhale.scss --> src/main.ts
```
These changes are applied when you run `yarn install` through a `postinstall` hook. If you want to modify these changes, check the `front/scripts/fix-fomantic-css.py` script.
### App styles
We plan to replace Fomantic with our own UI framework in the near future. Check our [Penpot](https://design.funkwhale.audio) to see what we've got planned.
```mermaid
graph TD
_css_vars --> /themes/_...
vendor/_media.scss --> _main.scss
/globals/_... --> _main.scss
/components/_... --> _main.scss
/pages/_... --> _main.scss
/themes/_... --> _main.scss
_vars.scss --> /themes/_...
```
## Components
Our [component library](https://ui.funkwhale.audio) contains reusable Vue components that you can add to the Funkwhale frontend. If you want to add a new component, check out [the repository](https://dev.funkwhale.audio/funkwhale/vui).
Start the **UI Live Docs** (vitepress) and follow the link:
```sh
yarn dev:docs
```
- Example: [Button component in the live docs](http://localhost:5173/components/ui/button)
- Find more details about the UI library and [how to contributein the live docs](http://localhost:5173/contributing)
<!-- prettier-ignore-start -->
(testing)=
## Testing
<!-- prettier-ignore-end -->
### Unit tests
The Funkwhale frontend contains some tests to catch errors before changes go live. The coverage is still fairly low, so we welcome any contributions.
To run the test suite, run the following command:
@ -34,3 +81,7 @@ To run tests as you make changes, launch the test suite with the `-w` flag:
```sh
docker compose run --rm front yarn test:unit -w
```
### End-to-end testing and User testing
In addition, there are End-to-end tests (cyprus), and we are planning to do User tests in 2025.

View File

@ -19,6 +19,12 @@ maxdepth: 1
objects
```
## How to use federation in the user interface
If you have the fediverse handle of a user ('xx@xx.xx'), displayed in their profile, you can paste this address in the global search field. Funkwhale will then clone the profile onto your instance and you will be able to see their profile locally and follow their activities. You are not automatically subscribed to their channels or have access to their public libraries. We still have to implement this in a [viable way] (https://dev.funkwhale.audio/funkwhale/funkwhale/-/issues/2422)
The same works for rss feeds that are outside of the fediverse. Just enter the RSS feed URI into the search field and you can add it as a podcast or music channel.
## Technologies and standards
Funkwhale's federation is built on top of the following technologies:

View File

@ -264,8 +264,7 @@ You can create local data to mimic a live environment.
Add some fake data to populate the database. The following command creates 25 artists with random albums, tracks, and metadata.
```sh
command="from funkwhale_api.music import fake_data; fake_data.create_data()"
echo $command | docker compose run --rm -T api funkwhale-manage shell -i python
docker compose exec -T api funkwhale-manage shell -i python <<< "from funkwhale_api.music import fake_data; fake_data.create_data(super_user_name='YOURNAMEHERE')"
```
This will launch a development funkwhale instance with a super user having `COMPOSE_PROJECT_NAME` as username and `funkwhale` as password. Libraries, listenings and music data will be associated with the superuser :
@ -416,11 +415,43 @@ To build the documentation locally run:
docker compose -f compose.docs.yml up -d
```
The documentation is then accessible at [https://docs.funkwhale.test](https://docs.funkwhale.test). The OpenAPI schema is available at [https://openapi.funkwhale.test](https://openapi.funkwhale.test).
The documentation is then accessible at [https://docs.funkwhale.test](https://docs.funkwhale.test). The OpenAPI schema is available at [https://openapi.funkwhale.test](https://openapi.funkwhale.test). The UI component library is available at [https://ui.funkwhale.test](https://ui.funkwhale.test).
Fallback ports are available for the documentation at
[http://localhost:8001/](http://localhost:8001/) and for the OpenAPI schema at
[http://localhost:8002/](http://localhost:8002/).
[http://localhost:8001/](http://localhost:8001/), for the OpenAPI schema at
[http://localhost:8002/](http://localhost:8002/) and for the UI component library at [http://localhost:8003/](http://localhost:8003/).
Maintain their life cycle with similar commands to those used to
[set up auxiliary services (point 2.)](#set-up-auxiliary-services).
## Running the test suites
Run the App test suite:
```sh
docker compose run --rm front yarn test
```
Run the App tests with coverage:
```sh
docker compose run --rm front yarn test:unit
```
<!-- prettier-ignore -->
Please also see the [Testing](<#testing>) in the App contributing guidelines.
Run the API test suite:
```sh
docker compose run --rm api pytest
```
Run a single test:
```sh
docker compose run --rm api pytest tests/music/test_models.py
```
<!-- prettier-ignore -->
Please also see [Run tests](<#runtests>) in the API contributing guidelines.

View File

@ -2,7 +2,7 @@
## Issue
We now have playlist, use complained about library not being clearly defined.
We now have playlists for sorting music and sharing, users complained about library not being clearly defined.
## Proposed solution
@ -14,7 +14,7 @@ A new endpoint to move upload from one library to another : `PATCH` on `api/v2/u
New `description` field on playlist, to inherit from the `description` field of Library
Library Follows will be transformed to user follow.
Library Follows will be transformed to user follows.
The schedule_scan function of the library still exist and allow federation of audio content
During user creation, built-in libraries are generated automatically by `create_user_libraries`

View File

@ -1,633 +0,0 @@
openapi: "3.0.3"
info:
description: "Interactive documentation for [Funkwhale](https://funkwhale.audio) API."
version: "2.0.0"
title: "Funkwhale API"
servers:
- url: "https://demo.funkwhale.audio"
description: "Demo server"
- url: "https://open.audio"
description: "Real server with real content"
- url: "https://{domain}"
description: "Custom server"
variables:
domain:
default: yourdomain
description: "Your Funkwhale Domain"
protocol:
enum:
- "http"
- "https"
default: "https"
tags:
- name: Instance
description: Information about the server
- name: Content
description: Information about content on the server
paths:
/api/v2/instance/nodeinfo/2.1:
get:
tags:
- Instance
summary: Retrieve nodeinfo data
description: Retrieve details about a Funkwhale server using the Nodeinfo standard
operationId: getNodeinfo
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/Nodeinfo"
application/xml:
schema:
$ref: "#/components/schemas/Nodeinfo"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v2/tags/podcasts:
get:
tags:
- Content
summary: Retrieve podcast categories
description: Retrieve a list of podcast categories and the number of uploads tagged with those categories
operationId: getTagsPodcasts
parameters:
- name: q
in: query
required: false
description: A free text field to filter category names
schema:
type: string
- name: page
in: query
required: false
description: The number of the result page you want to return
schema:
type: number
- name: page_size
in: query
required: false
description: The number of results to return on each page. Defaults to 50.
schema:
type: number
- name: ordering
in: query
required: false
description: |
The order in which results are presented. Preface with `-` to return items in descending order.
schema:
type: string
enum:
- "name"
- "creation_date"
- "tagged_items"
- "-name"
- "-creation_date"
- "-tagged_items"
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/Categories"
application/xml:
schema:
$ref: "#/components/schemas/Categories"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v2/tags/podcasts/{category}:
get:
tags:
- Content
summary: Retrieve podcast categories
description: Retrieve a list of podcast categories and the number of uploads tagged with those categories
operationId: getTagPodcasts
parameters:
- name: category
in: path
required: true
description: The category you want to return information about
schema:
type: string
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/Category"
application/xml:
schema:
$ref: "#/components/schemas/Category"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v2/tags/music:
get:
tags:
- Content
summary: Retrieve music genres
description: Retrieve a list of music genres and the number of uploads tagged with those categories
operationId: getTagsMusic
parameters:
- name: q
in: query
required: false
description: A free text field to filter genre names
schema:
type: string
- name: page
in: query
required: false
description: The number of the result page you want to return
schema:
type: number
- name: page_size
in: query
required: false
description: The number of results to return on each page. Defaults to 50.
schema:
type: number
- name: ordering
in: query
required: false
description: |
The order in which results are presented. Preface with `-` to return items in descending order.
schema:
type: string
enum:
- "name"
- "creation_date"
- "tagged_items"
- "-name"
- "-creation_date"
- "-tagged_items"
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/Genres"
application/xml:
schema:
$ref: "#/components/schemas/Genres"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v2/tags/music/{genre}:
get:
tags:
- Content
summary: Retrieve podcast categories
description: Retrieve a list of podcast categories and the number of uploads tagged with those categories
operationId: getTagMusic
parameters:
- name: genre
in: path
required: true
description: The genre you want to return information about
schema:
type: string
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/Genre"
application/xml:
schema:
$ref: "#/components/schemas/Genre"
"401":
$ref: "#/components/responses/Unauthorized"
components:
responses:
Unauthorized:
description: Unauthorized
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
code: 401
message: User not authorized
application/xml:
schema:
$ref: "#/components/schemas/Error"
example:
code: 401
message: User not authorized
schemas:
Categories:
type: object
properties:
total:
type: number
next:
type: string
format: url
previous:
type: string
format: url
results:
type: array
items:
$ref: "#/components/schemas/Category"
example:
total: 5
next: https://demo.funkwhale.audio/api/v2/categories?page=2&page_size=2&q=crime
previous: null
results:
- category: "True Crime"
created_date: "2020-01-01T00:00:00.000Z"
tagged_items: 5
results_page: "https://demo.funkwhale.audio/library/categories/True%20Crime"
- category: "True Stories"
created_date: "2023-12-15T23:32:52.000Z"
tagged_items: 200
results_page: "https://demo.funkwhale.audio/library/categories/True%20Stories"
Category:
type: object
properties:
category:
type: string
created_date:
type: string
format: date-time
tagged_items:
type: number
results_page:
type: string
format: url
example:
category: "True Crime"
created_date: "2020-01-01T00:00:00.000Z"
tagged_items: 5
results_page: "https://demo.funkwhale.audio/library/categories/True%20Crime"
Genres:
type: object
properties:
total:
type: number
next:
type: string
format: url
previous:
type: string
format: url
results:
type: array
items:
$ref: "#/components/schemas/Genre"
example:
total: 5
next: https://demo.funkwhale.audio/api/v2/categories?page=2&page_size=2&q=rock
previous: null
results:
- genre: "Acoustic Rock"
created_date: "2020-01-01T00:00:00.000Z"
tagged_items: 5
results_page: "https://demo.funkwhale.audio/library/categories/Acoustic%20Rock"
- genre: "Surf Rock"
created_date: "2023-12-15T23:32:52.000Z"
tagged_items: 200
results_page: "https://demo.funkwhale.audio/library/categories/Surf%20Rock"
Genre:
type: object
properties:
genre:
type: string
created_date:
type: string
format: date-time
tagged_items:
type: number
results_page:
type: string
format: url
example:
genre: "Acoustic Rock"
created_date: "2020-01-01T00:00:00.000Z"
tagged_items: 5
results_page: "https://demo.funkwhale.audio/library/categories/Acoustic%20Rock"
Nodeinfo:
type: object
required:
- version
- software
- protocols
- services
- openRegistrations
- usage
- metadata
properties:
version:
type: string
enum:
- "2.1"
software:
type: object
required:
- name
- version
properties:
name:
type: string
enum:
- "Funkwhale"
version:
type: string
example: "1.4.0"
repository:
type: string
format: url
enum:
- "https://dev.funkwhale.audio/funkwhale/funkwhale"
homepage:
type: string
format: url
enum:
- "https://funkwhale.audio"
protocols:
type: array
minItems: 1
items:
type: string
enum:
- "activitypub"
- "buddycloud"
- "dfrn"
- "diaspora"
- "libertree"
- "ostatus"
- "pumpio"
- "tent"
- "xmpp"
- "zot"
example:
- "activitypub"
services:
type: object
required:
- inbound
- outbound
properties:
inbound:
type: array
items:
type: string
enum:
- "atom1.0"
- "gnusocial"
- "imap"
- "pnut"
- "pop3"
- "pumpio"
- "rss2.0"
- "twitter"
outbound:
type: array
items:
type: string
enum:
- "atom1.0"
- "blogger"
- "buddycloud"
- "diaspora"
- "dreamwidth"
- "drupal"
- "facebook"
- "friendica"
- "gnusocial"
- "google"
- "insanejournal"
- "libertree"
- "linkedin"
- "livejournal"
- "mediagoblin"
- "myspace"
- "pinterest"
- "pnut"
- "posterous"
- "pumpio"
- "redmatrix"
- "rss2.0"
- "smtp"
- "tent"
- "tumblr"
- "twitter"
- "wordpress"
- "xmpp"
openRegistrations:
type: boolean
usage:
type: object
required:
- users
properties:
users:
type: object
properties:
total:
type: integer
minimum: 0
activeHalfYear:
type: integer
minimum: 0
activeMonth:
type: integer
minimum: 0
localPosts:
type: integer
minimum: 0
localComments:
type: integer
minimum: 0
metadata:
type: object
properties:
actorId:
type: string
format: url
private:
type: boolean
shortDescription:
type: string
longDescription:
type: string
contactEmail:
type: string
format: email
nodeName:
type: string
banner:
type: string
format: url
nullable: true
defaultUploadQuota:
type: integer
supportedUploadExtensions:
type: array
items:
type: string
allowList:
type: object
properties:
enabled:
type: boolean
domains:
type: array
nullable: true
items:
type: string
funkwhaleSupportMessageEnabled:
type: boolean
instanceSupportMessage:
type: string
languages:
type: array
items:
type: string
location:
type: string
codeOfConduct:
type: string
format: url
content:
type: object
properties:
local:
type: object
properties:
artists:
type: number
releases:
type: number
recordings:
type: number
hoursOfContent:
type: number
example:
artists: 1000
releases: 10000
recordings: 150000
hoursOfContent: 7500
topMusicCategories:
type: array
items:
type: object
properties:
name:
type: string
count:
type: integer
minimum: 0
example:
- name: "rock"
count: 1256
- name: "jazz"
count: 604
- name: "classical"
count: 308
topPodcastCategories:
type: array
items:
type: object
properties:
name:
type: string
count:
type: integer
minimum: 0
example:
- name: "comedy"
count: 12
- name: "politics"
count: 4
- name: "nature"
count: 1
federation:
type: object
properties:
followedInstances:
type: integer
followingInstances:
type: integer
usage:
type: object
properties:
listenings:
type: integer
minimum: 0
downloads:
type: integer
minimum: 0
favorites:
type: object
properties:
tracks:
type: integer
minimum: 0
features:
type: array
items:
type: string
example:
- "channels"
- "podcasts"
- "collections"
- "audiobooks"
- "federation"
- "anonymousCanListen"
- "onlyMbidTaggedContent"
Error:
type: object
properties:
code:
type: string
message:
type: string
required:
- code
- message
securitySchemes:
oauth2:
type: oauth2
description: This API uses OAuth 2 with the Authorization Code flow. You can register an app using the /oauth/apps/ endpoint.
flows:
authorizationCode:
authorizationUrl: /authorize
tokenUrl: /api/v1/oauth/token/
refreshUrl: /api/v1/oauth/token/
scopes:
"read": "Read-only access to all user data"
"write": "Write-only access on all user data"
"read:edits": "Read-only access to edits"
"write:edits": "Write-only access to edits"
"read:favorites": "Read-only access to favorites"
"write:favorites": "Write-only access to favorits"
"read:filters": "Read-only to to content filters"
"write:filters": "Write-only access to content-filters"
"read:follows": "Read-only to follows"
"write:follows": "Write-only access to follows"
"read:libraries": "Read-only access to library and uploads"
"write:libraries": "Write-only access to libraries"
"read:listenings": "Read-only access to listening history"
"write:listenings": "Write-only access to listening history"
"read:notifications": "Read-only access to notifications"
"write:notifications": "Write-only access to notifications"
"read:playlists": "Read-only access to playlists"
"write:playlists": "Write-only access to playlists"
"read:profile": "Read-only access to profile data"
"write:profile": "Write-only access to profile data"
"read:radios": "Read-only access to radios"
"write:radios": "Write-only access to radios"
"read:reports": "Read-only access to reports"
"write:reports": "Write-only access to reports"
"read:security": "Read-only access security settings"
"write:security": "write-only access security settings"
security:
- oauth2: []

View File

@ -0,0 +1 @@
../../../api/funkwhale_api/common/schema.yml