From cbd0ba2872f032e04e6d20c124b61042309fb218 Mon Sep 17 00:00:00 2001 From: jon r Date: Fri, 18 Apr 2025 11:24:50 +0200 Subject: [PATCH] Docs: update for new UI, schema, debugging and federation Co-Authored-By: ArneBo Co-Authored-By: Flupsi Co-Authored-By: jon r --- docs/developer/contribute/api.md | 5 + docs/developer/contribute/copy.md | 8 +- docs/developer/contribute/frontend.md | 65 ++- docs/developer/federation/index.md | 6 + docs/developer/setup/docker.md | 41 +- docs/specs/library-drop/index.md | 4 +- docs/specs/nodeinfo21/schema.yml | 634 +------------------------- 7 files changed, 112 insertions(+), 651 deletions(-) mode change 100644 => 120000 docs/specs/nodeinfo21/schema.yml diff --git a/docs/developer/contribute/api.md b/docs/developer/contribute/api.md index c9bfd07f8..4f8099734 100644 --- a/docs/developer/contribute/api.md +++ b/docs/developer/contribute/api.md @@ -129,8 +129,13 @@ def test_downgrade_not_superuser_skips_email(factories, mocker): mocked_notify.assert_not_called() ``` + + +(runtests)= ## Run tests + + You can run all tests in the pytest suite with the following command: ```sh diff --git a/docs/developer/contribute/copy.md b/docs/developer/contribute/copy.md index 407ecb21d..c2acba76d 100644 --- a/docs/developer/contribute/copy.md +++ b/docs/developer/contribute/copy.md @@ -47,8 +47,8 @@ const labels = computed(() => ({ :::{tab-item} Template ```html -

{{ $t('components.About.header.funkwhale') }}

- +

{{ t('components.About.header.funkwhale') }}

+ ``` ::: @@ -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}) }} - {{ $t('components.audio.ChannelCard.meta.tracks', {tracks_count: + {{ t('components.audio.ChannelCard.meta.tracks', {tracks_count: object.artist?.tracks_count}) }} -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) + + + +(testing)= ## Testing + + +### 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. diff --git a/docs/developer/federation/index.md b/docs/developer/federation/index.md index 59fd7bc51..8a5a8047e 100644 --- a/docs/developer/federation/index.md +++ b/docs/developer/federation/index.md @@ -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: diff --git a/docs/developer/setup/docker.md b/docs/developer/setup/docker.md index 283259ecc..e55091352 100644 --- a/docs/developer/setup/docker.md +++ b/docs/developer/setup/docker.md @@ -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 +``` + + +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 +``` + + +Please also see [Run tests](<#runtests>) in the API contributing guidelines. diff --git a/docs/specs/library-drop/index.md b/docs/specs/library-drop/index.md index c897f87b4..40cb2ec08 100644 --- a/docs/specs/library-drop/index.md +++ b/docs/specs/library-drop/index.md @@ -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` diff --git a/docs/specs/nodeinfo21/schema.yml b/docs/specs/nodeinfo21/schema.yml deleted file mode 100644 index 58035c2db..000000000 --- a/docs/specs/nodeinfo21/schema.yml +++ /dev/null @@ -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: [] diff --git a/docs/specs/nodeinfo21/schema.yml b/docs/specs/nodeinfo21/schema.yml new file mode 120000 index 000000000..679eddb56 --- /dev/null +++ b/docs/specs/nodeinfo21/schema.yml @@ -0,0 +1 @@ +../../../api/funkwhale_api/common/schema.yml \ No newline at end of file