diff --git a/src/api/alias/index.ts b/src/api/alias/index.ts index d7346f335..fa31f44b7 100644 --- a/src/api/alias/index.ts +++ b/src/api/alias/index.ts @@ -10,9 +10,11 @@ import { DeleteApiRequestBuilder } from '../common/api-request-builder/delete-ap /** * Adds an alias to an existing note. + * * @param noteIdOrAlias The note id or an existing alias for a note. * @param newAlias The new alias. * @return Information about the newly created alias. + * @throws {Error} when the api request wasn't successfull */ export const addAlias = async (noteIdOrAlias: string, newAlias: string): Promise => { const response = await new PostApiRequestBuilder('alias') @@ -27,8 +29,10 @@ export const addAlias = async (noteIdOrAlias: string, newAlias: string): Promise /** * Marks a given alias as the primary one for a note. * The former primary alias should be marked as non-primary by the backend automatically. + * * @param alias The alias to mark as primary for its corresponding note. * @return The updated information about the alias. + * @throws {Error} when the api request wasn't successfull */ export const markAliasAsPrimary = async (alias: string): Promise => { const response = await new PutApiRequestBuilder('alias/' + alias) @@ -41,7 +45,9 @@ export const markAliasAsPrimary = async (alias: string): Promise => { /** * Removes a given alias from its corresponding note. + * * @param alias The alias to remove from its note. + * @throws {Error} when the api request wasn't successful. */ export const deleteAlias = async (alias: string): Promise => { await new DeleteApiRequestBuilder('alias/' + alias).sendRequest() diff --git a/src/api/auth/index.ts b/src/api/auth/index.ts index 737a369b1..b8a4f74ae 100644 --- a/src/api/auth/index.ts +++ b/src/api/auth/index.ts @@ -7,7 +7,8 @@ import { DeleteApiRequestBuilder } from '../common/api-request-builder/delete-ap /** * Requests to log out the current user. - * @throws Error if logout is not possible. + * + * @throws {Error} if logout is not possible. */ export const doLogout = async (): Promise => { await new DeleteApiRequestBuilder('auth/logout').sendRequest() diff --git a/src/api/auth/ldap.ts b/src/api/auth/ldap.ts index 43d5bd28a..a3456a3d6 100644 --- a/src/api/auth/ldap.ts +++ b/src/api/auth/ldap.ts @@ -9,11 +9,13 @@ import { AuthError } from './types' import { PostApiRequestBuilder } from '../common/api-request-builder/post-api-request-builder' /** - * Requests to login a user via LDAP credentials. + * Requests to log in a user via LDAP credentials. + * * @param provider The identifier of the LDAP provider with which to login. * @param username The username with which to try the login. * @param password The password of the user. * @throws {AuthError.INVALID_CREDENTIALS} if the LDAP provider denied the given credentials. + * @throws {Error} when the api request wasn't successfull */ export const doLdapLogin = async (provider: string, username: string, password: string): Promise => { await new PostApiRequestBuilder('auth/ldap/' + provider) diff --git a/src/api/auth/local.ts b/src/api/auth/local.ts index 78afb28ea..2bf7becf2 100644 --- a/src/api/auth/local.ts +++ b/src/api/auth/local.ts @@ -10,10 +10,12 @@ import { PutApiRequestBuilder } from '../common/api-request-builder/put-api-requ /** * Requests to do a local login with a provided username and password. + * * @param username The username for which the login should be tried. * @param password The password which should be used to log in. * @throws {AuthError.INVALID_CREDENTIALS} when the username or password is wrong. * @throws {AuthError.LOGIN_DISABLED} when the local login is disabled on the backend. + * @throws {Error} when the api request wasn't successful. */ export const doLocalLogin = async (username: string, password: string): Promise => { await new PostApiRequestBuilder('auth/local/login') @@ -30,11 +32,13 @@ export const doLocalLogin = async (username: string, password: string): Promise< /** * Requests to register a new local user in the backend. + * * @param username The username of the new user. * @param displayName The display name of the new user. * @param password The password of the new user. * @throws {RegisterError.USERNAME_EXISTING} when there is already an existing user with the same username. * @throws {RegisterError.REGISTRATION_DISABLED} when the registration of local users has been disabled on the backend. + * @throws {Error} when the api request wasn't successful. */ export const doLocalRegister = async (username: string, displayName: string, password: string): Promise => { await new PostApiRequestBuilder('auth/local') diff --git a/src/api/common/api-request-builder/api-request-builder-with-body.ts b/src/api/common/api-request-builder/api-request-builder-with-body.ts index f26df7a4b..23bdc0ab0 100644 --- a/src/api/common/api-request-builder/api-request-builder-with-body.ts +++ b/src/api/common/api-request-builder/api-request-builder-with-body.ts @@ -29,7 +29,7 @@ export abstract class ApiRequestBuilderWithBody e * * @param bodyData The data to use as request body. Will get stringified to JSON. * @return The API request instance itself for chaining. - * @see {withBody} + * @see withBody */ withJsonBody(bodyData: RequestBodyType): this { this.withHeader('Content-Type', 'application/json') diff --git a/src/api/common/api-request-builder/api-request-builder.ts b/src/api/common/api-request-builder/api-request-builder.ts index 0fbb29583..f8cffb219 100644 --- a/src/api/common/api-request-builder/api-request-builder.ts +++ b/src/api/common/api-request-builder/api-request-builder.ts @@ -108,7 +108,7 @@ export abstract class ApiRequestBuilder { * Send the prepared API call as a GET request. A default status code of 200 is expected. * * @return The API response. - * @throws Error when the status code does not match the expected one or is defined as in the custom status code + * @throws {Error} when the status code does not match the expected one or is defined as in the custom status code * error mapping. */ abstract sendRequest(): Promise> diff --git a/src/api/common/api-request-builder/delete-api-request-builder.ts b/src/api/common/api-request-builder/delete-api-request-builder.ts index 8191edde3..b1c37247b 100644 --- a/src/api/common/api-request-builder/delete-api-request-builder.ts +++ b/src/api/common/api-request-builder/delete-api-request-builder.ts @@ -11,14 +11,14 @@ import { ApiRequestBuilderWithBody } from './api-request-builder-with-body' * * @param ResponseType The type of the expected response. Defaults to no response body. * @param RequestBodyType The type of the request body. Defaults to no request body. - * @see {ApiRequestBuilder} + * @see ApiRequestBuilder */ export class DeleteApiRequestBuilder extends ApiRequestBuilderWithBody< ResponseType, RequestBodyType > { /** - * @see {ApiRequestBuilder#sendRequest} + * @see ApiRequestBuilder#sendRequest */ sendRequest(): Promise> { return this.sendRequestAndVerifyResponse('DELETE', 204) diff --git a/src/api/common/api-request-builder/get-api-request-builder.ts b/src/api/common/api-request-builder/get-api-request-builder.ts index ffe2bcf12..ce995effa 100644 --- a/src/api/common/api-request-builder/get-api-request-builder.ts +++ b/src/api/common/api-request-builder/get-api-request-builder.ts @@ -11,11 +11,11 @@ import type { ApiResponse } from '../api-response' * Builder to construct a GET request to the API. * * @param ResponseType The type of the expected response. - * @see {ApiRequestBuilder} + * @see ApiRequestBuilder */ export class GetApiRequestBuilder extends ApiRequestBuilder { /** - * @see {ApiRequestBuilder#sendRequest} + * @see ApiRequestBuilder#sendRequest */ sendRequest(): Promise> { return this.sendRequestAndVerifyResponse('GET', 200) diff --git a/src/api/common/api-request-builder/post-api-request-builder.ts b/src/api/common/api-request-builder/post-api-request-builder.ts index e2168d689..8c7b6b16d 100644 --- a/src/api/common/api-request-builder/post-api-request-builder.ts +++ b/src/api/common/api-request-builder/post-api-request-builder.ts @@ -11,14 +11,14 @@ import { ApiRequestBuilderWithBody } from './api-request-builder-with-body' * * @param ResponseType The type of the expected response. * @param RequestBodyType The type of the request body - * @see {ApiRequestBuilder} + * @see ApiRequestBuilder */ export class PostApiRequestBuilder extends ApiRequestBuilderWithBody< ResponseType, RequestBodyType > { /** - * @see {ApiRequestBuilder#sendRequest} + * @see ApiRequestBuilder#sendRequest */ sendRequest(): Promise> { return this.sendRequestAndVerifyResponse('POST', 201) diff --git a/src/api/common/api-request-builder/put-api-request-builder.ts b/src/api/common/api-request-builder/put-api-request-builder.ts index 7f0381766..aa39fe223 100644 --- a/src/api/common/api-request-builder/put-api-request-builder.ts +++ b/src/api/common/api-request-builder/put-api-request-builder.ts @@ -11,14 +11,14 @@ import { ApiRequestBuilderWithBody } from './api-request-builder-with-body' * * @param ResponseType The type of the expected response. * @param RequestBodyType The type of the request body - * @see {ApiRequestBuilder} + * @see ApiRequestBuilder */ export class PutApiRequestBuilder extends ApiRequestBuilderWithBody< ResponseType, RequestBodyType > { /** - * @see {ApiRequestBuilder#sendRequest} + * @see ApiRequestBuilder#sendRequest */ sendRequest(): Promise> { return this.sendRequestAndVerifyResponse('PUT', 200) diff --git a/src/api/common/api-request-builder/test-utils/expect-fetch.ts b/src/api/common/api-request-builder/test-utils/expect-fetch.ts index 3993671cb..e8c1d522a 100644 --- a/src/api/common/api-request-builder/test-utils/expect-fetch.ts +++ b/src/api/common/api-request-builder/test-utils/expect-fetch.ts @@ -7,7 +7,15 @@ import { defaultConfig } from '../../default-config' import { Mock } from 'ts-mockery' -export const expectFetch = (expectedUrl: string, expectedStatusCode: number, expectedOptions: RequestInit): void => { +/** + * Mock fetch api for tests. + * Check that the given url and options are present in the request and return the given status code. + * + * @param expectedUrl the url that should be requested + * @param requestStatusCode the status code the mocked request should return + * @param expectedOptions additional options + */ +export const expectFetch = (expectedUrl: string, requestStatusCode: number, expectedOptions: RequestInit): void => { global.fetch = jest.fn((fetchUrl: RequestInfo | URL, fetchOptions?: RequestInit): Promise => { expect(fetchUrl).toEqual(expectedUrl) expect(fetchOptions).toStrictEqual({ @@ -18,7 +26,7 @@ export const expectFetch = (expectedUrl: string, expectedStatusCode: number, exp }) return Promise.resolve( Mock.of({ - status: expectedStatusCode + status: requestStatusCode }) ) }) diff --git a/src/api/common/api-response.ts b/src/api/common/api-response.ts index 58f891b71..d8eca4ad1 100644 --- a/src/api/common/api-response.ts +++ b/src/api/common/api-response.ts @@ -12,6 +12,7 @@ export class ApiResponse { /** * Initializes a new API response instance based on an HTTP response. + * * @param response The HTTP response from the fetch call. */ constructor(response: Response) { @@ -31,7 +32,7 @@ export class ApiResponse { * Returns the response as parsed JSON. An error will be thrown if the response is not JSON encoded. * * @return The parsed JSON response. - * @throws Error if the response is not JSON encoded. + * @throws {Error} if the response is not JSON encoded. */ async asParsedJsonObject(): Promise { if (!this.response.headers.get('Content-Type')?.startsWith('application/json')) { diff --git a/src/api/config/index.ts b/src/api/config/index.ts index 5c13f5600..8d45d73eb 100644 --- a/src/api/config/index.ts +++ b/src/api/config/index.ts @@ -9,7 +9,9 @@ import { GetApiRequestBuilder } from '../common/api-request-builder/get-api-requ /** * Fetches the frontend config from the backend. + * * @return The frontend config. + * @throws {Error} when the api request wasn't successful. */ export const getConfig = async (): Promise => { const response = await new GetApiRequestBuilder('config').sendRequest() diff --git a/src/api/group/index.ts b/src/api/group/index.ts index 7bef46f3a..ccfd754d5 100644 --- a/src/api/group/index.ts +++ b/src/api/group/index.ts @@ -9,8 +9,10 @@ import { GetApiRequestBuilder } from '../common/api-request-builder/get-api-requ /** * Retrieves information about a group with a given name. + * * @param groupName The name of the group. * @return Information about the group. + * @throws {Error} when the api request wasn't successful. */ export const getGroup = async (groupName: string): Promise => { const response = await new GetApiRequestBuilder('groups/' + groupName).sendRequest() diff --git a/src/api/history/dto-methods.ts b/src/api/history/dto-methods.ts index 3028b79a9..ab3c25d62 100644 --- a/src/api/history/dto-methods.ts +++ b/src/api/history/dto-methods.ts @@ -1,18 +1,30 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ import type { HistoryEntry, HistoryEntryPutDto, HistoryEntryWithOrigin } from './types' import { HistoryEntryOrigin } from './types' -export const addRemoteOriginToHistoryEntry = (entryDto: HistoryEntry): HistoryEntryWithOrigin => { +/** + * Transform a {@link HistoryEntry} into a {@link HistoryEntryWithOrigin}. + * + * @param entry the entry to build from + * @return the history entry with an origin + */ +export const addRemoteOriginToHistoryEntry = (entry: HistoryEntry): HistoryEntryWithOrigin => { return { - ...entryDto, + ...entry, origin: HistoryEntryOrigin.REMOTE } } +/** + * Create a {@link HistoryEntryPutDto} from a {@link HistoryEntry}. + * + * @param entry the entry to build the dto from + * @return the dto for the api + */ export const historyEntryToHistoryEntryPutDto = (entry: HistoryEntry): HistoryEntryPutDto => { return { pinStatus: entry.pinStatus, diff --git a/src/api/history/index.ts b/src/api/history/index.ts index 906409497..2921fd655 100644 --- a/src/api/history/index.ts +++ b/src/api/history/index.ts @@ -11,7 +11,9 @@ import { DeleteApiRequestBuilder } from '../common/api-request-builder/delete-ap /** * Fetches the remote history for the user from the server. + * * @return The remote history entries of the user. + * @throws {Error} when the api request wasn't successful. */ export const getRemoteHistory = async (): Promise => { const response = await new GetApiRequestBuilder('me/history').sendRequest() @@ -20,7 +22,9 @@ export const getRemoteHistory = async (): Promise => { /** * Replaces the remote history of the user with the given history entries. + * * @param entries The history entries to store remotely. + * @throws {Error} when the api request wasn't successful. */ export const setRemoteHistoryEntries = async (entries: HistoryEntryPutDto[]): Promise => { await new PostApiRequestBuilder('me/history').withJsonBody(entries).sendRequest() @@ -28,8 +32,10 @@ export const setRemoteHistoryEntries = async (entries: HistoryEntryPutDto[]): Pr /** * Updates a remote history entry's pin state. + * * @param noteIdOrAlias The note id for which to update the pinning state. * @param pinStatus True when the note should be pinned, false otherwise. + * @throws {Error} when the api request wasn't successful. */ export const updateRemoteHistoryEntryPinStatus = async ( noteIdOrAlias: string, @@ -45,7 +51,9 @@ export const updateRemoteHistoryEntryPinStatus = async ( /** * Deletes a remote history entry. + * * @param noteIdOrAlias The note id or alias of the history entry to remove. + * @throws {Error} when the api request wasn't successful. */ export const deleteRemoteHistoryEntry = async (noteIdOrAlias: string): Promise => { await new DeleteApiRequestBuilder('me/history/' + noteIdOrAlias).sendRequest() @@ -53,6 +61,8 @@ export const deleteRemoteHistoryEntry = async (noteIdOrAlias: string): Promise => { await new DeleteApiRequestBuilder('me/history').sendRequest() diff --git a/src/api/me/index.ts b/src/api/me/index.ts index 9d065e894..07937d20c 100644 --- a/src/api/me/index.ts +++ b/src/api/me/index.ts @@ -11,8 +11,9 @@ import { PostApiRequestBuilder } from '../common/api-request-builder/post-api-re /** * Returns metadata about the currently signed-in user from the API. - * @throws Error when the user is not signed-in. + * * @return The user metadata. + * @throws {Error} when the user is not signed-in. */ export const getMe = async (): Promise => { const response = await new GetApiRequestBuilder('me').sendRequest() @@ -21,6 +22,8 @@ export const getMe = async (): Promise => { /** * Deletes the current user from the server. + * + * @throws {Error} when the api request wasn't successful. */ export const deleteUser = async (): Promise => { await new DeleteApiRequestBuilder('me').sendRequest() @@ -28,7 +31,9 @@ export const deleteUser = async (): Promise => { /** * Changes the display name of the current user. + * * @param displayName The new display name to set. + * @throws {Error} when the api request wasn't successful. */ export const updateDisplayName = async (displayName: string): Promise => { await new PostApiRequestBuilder('me/profile') @@ -40,7 +45,9 @@ export const updateDisplayName = async (displayName: string): Promise => { /** * Retrieves a list of media belonging to the user. + * * @return List of media object information. + * @throws {Error} when the api request wasn't successful. */ export const getMyMedia = async (): Promise => { const response = await new GetApiRequestBuilder('me/media').sendRequest() diff --git a/src/api/media/index.ts b/src/api/media/index.ts index 44b869dc8..b9b3fe314 100644 --- a/src/api/media/index.ts +++ b/src/api/media/index.ts @@ -9,8 +9,10 @@ import { DeleteApiRequestBuilder } from '../common/api-request-builder/delete-ap /** * Requests an image-proxy URL from the backend for a given image URL. + * * @param imageUrl The image URL which should be proxied. * @return The proxy URL for the image. + * @throws {Error} when the api request wasn't successful. */ export const getProxiedUrl = async (imageUrl: string): Promise => { const response = await new PostApiRequestBuilder('media/proxy') @@ -23,9 +25,11 @@ export const getProxiedUrl = async (imageUrl: string): Promise => { const postData = new FormData() @@ -40,7 +44,9 @@ export const uploadFile = async (noteIdOrAlias: string, media: Blob): Promise => { await new DeleteApiRequestBuilder('media/' + mediaId).sendRequest() diff --git a/src/api/notes/index.ts b/src/api/notes/index.ts index d6c7382ec..71384168e 100644 --- a/src/api/notes/index.ts +++ b/src/api/notes/index.ts @@ -11,8 +11,10 @@ import { DeleteApiRequestBuilder } from '../common/api-request-builder/delete-ap /** * Retrieves the content and metadata about the specified note. + * * @param noteIdOrAlias The id or alias of the note. * @return Content and metadata of the specified note. + * @throws {Error} when the api request wasn't successful. */ export const getNote = async (noteIdOrAlias: string): Promise => { const response = await new GetApiRequestBuilder('notes/' + noteIdOrAlias) @@ -23,8 +25,10 @@ export const getNote = async (noteIdOrAlias: string): Promise => { /** * Returns a list of media objects associated with the specified note. + * * @param noteIdOrAlias The id or alias of the note. * @return List of media object metadata associated with specified note. + * @throws {Error} when the api request wasn't successful. */ export const getMediaForNote = async (noteIdOrAlias: string): Promise => { const response = await new GetApiRequestBuilder(`notes/${noteIdOrAlias}/media`).sendRequest() @@ -33,8 +37,10 @@ export const getMediaForNote = async (noteIdOrAlias: string): Promise => { const response = await new PostApiRequestBuilder('notes') @@ -46,9 +52,11 @@ export const createNote = async (markdown: string): Promise => { /** * Creates a new note with a given markdown content and a defined primary alias. + * * @param markdown The content of the new note. * @param primaryAlias The primary alias of the new note. * @return Content and metadata of the new note. + * @throws {Error} when the api request wasn't successful. */ export const createNoteWithPrimaryAlias = async (markdown: string, primaryAlias: string): Promise => { const response = await new PostApiRequestBuilder('notes/' + primaryAlias) @@ -60,7 +68,9 @@ export const createNoteWithPrimaryAlias = async (markdown: string, primaryAlias: /** * Deletes the specified note. + * * @param noteIdOrAlias The id or alias of the note to delete. + * @throws {Error} when the api request wasn't successful. */ export const deleteNote = async (noteIdOrAlias: string): Promise => { await new DeleteApiRequestBuilder('notes/' + noteIdOrAlias).sendRequest() diff --git a/src/api/permissions/index.ts b/src/api/permissions/index.ts index 3f152c487..2a7837693 100644 --- a/src/api/permissions/index.ts +++ b/src/api/permissions/index.ts @@ -10,9 +10,11 @@ import { DeleteApiRequestBuilder } from '../common/api-request-builder/delete-ap /** * Sets the owner of a note. + * * @param noteId The id of the note. * @param owner The username of the new owner. - * @return The updated note permissions. + * @return The updated {@link NotePermissions}. + * @throws {Error} when the api request wasn't successful. */ export const setNoteOwner = async (noteId: string, owner: string): Promise => { const response = await new PutApiRequestBuilder( @@ -27,9 +29,12 @@ export const setNoteOwner = async (noteId: string, owner: string): Promise => { const response = await new DeleteApiRequestBuilder( @@ -83,8 +94,11 @@ export const removeUserPermission = async (noteId: string, username: string): Pr /** * Removes the permissions of a note for a group. + * * @param noteId The id of the note. * @param groupName The name of the group to remove the permission of. + * @return The updated {@link NotePermissions}. + * @throws {Error} when the api request wasn't successful. */ export const removeGroupPermission = async (noteId: string, groupName: string): Promise => { const response = await new DeleteApiRequestBuilder( diff --git a/src/api/revisions/index.ts b/src/api/revisions/index.ts index 299b8cbaf..45e0c97a2 100644 --- a/src/api/revisions/index.ts +++ b/src/api/revisions/index.ts @@ -9,9 +9,11 @@ import { DeleteApiRequestBuilder } from '../common/api-request-builder/delete-ap /** * Retrieves a note revision while using a cache for often retrieved revisions. + * * @param noteId The id of the note for which to fetch the revision. * @param revisionId The id of the revision to fetch. * @return The revision. + * @throws {Error} when the api request wasn't successful. */ export const getRevision = async (noteId: string, revisionId: number): Promise => { const response = await new GetApiRequestBuilder( @@ -22,8 +24,10 @@ export const getRevision = async (noteId: string, revisionId: number): Promise => { const response = await new GetApiRequestBuilder(`notes/${noteId}/revisions`).sendRequest() @@ -32,7 +36,9 @@ export const getAllRevisions = async (noteId: string): Promise => { await new DeleteApiRequestBuilder(`notes/${noteIdOrAlias}/revisions`).sendRequest() diff --git a/src/api/tokens/index.ts b/src/api/tokens/index.ts index e4b557fd2..608c38ad5 100644 --- a/src/api/tokens/index.ts +++ b/src/api/tokens/index.ts @@ -10,7 +10,9 @@ import { DeleteApiRequestBuilder } from '../common/api-request-builder/delete-ap /** * Retrieves the access tokens for the current user. + * * @return List of access token metadata. + * @throws {Error} when the api request wasn't successful. */ export const getAccessTokenList = async (): Promise => { const response = await new GetApiRequestBuilder('tokens').sendRequest() @@ -19,9 +21,11 @@ export const getAccessTokenList = async (): Promise => { /** * Creates a new access token for the current user. + * * @param label The user-defined label for the new access token. * @param validUntil The user-defined expiry date of the new access token in milliseconds of unix time. * @return The new access token metadata along with its secret. + * @throws {Error} when the api request wasn't successful. */ export const postNewAccessToken = async (label: string, validUntil: number): Promise => { const response = await new PostApiRequestBuilder('tokens') @@ -35,7 +39,9 @@ export const postNewAccessToken = async (label: string, validUntil: number): Pro /** * Removes an access token from the current user account. + * * @param keyId The key id of the access token to delete. + * @throws {Error} when the api request wasn't successful. */ export const deleteAccessToken = async (keyId: string): Promise => { await new DeleteApiRequestBuilder('tokens/' + keyId).sendRequest() diff --git a/src/api/users/index.ts b/src/api/users/index.ts index 242ae9d31..e022b2cca 100644 --- a/src/api/users/index.ts +++ b/src/api/users/index.ts @@ -9,8 +9,10 @@ import { GetApiRequestBuilder } from '../common/api-request-builder/get-api-requ /** * Retrieves information about a specific user while using a cache to avoid many requests for the same username. + * * @param username The username of interest. * @return Metadata about the requested user. + * @throws {Error} when the api request wasn't successful. */ export const getUser = async (username: string): Promise => { const response = await new GetApiRequestBuilder('users/' + username).sendRequest() diff --git a/src/components/application-loader/application-loader-error.ts b/src/components/application-loader/application-loader-error.ts index b2efc1a2b..355ebbf6b 100644 --- a/src/components/application-loader/application-loader-error.ts +++ b/src/components/application-loader/application-loader-error.ts @@ -1,8 +1,11 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ +/** + * Custom {@link Error} class for the {@link ApplicationLoader}. + */ export class ApplicationLoaderError extends Error { constructor(taskName: string) { super(`The task ${taskName} failed`) diff --git a/src/components/application-loader/application-loader.tsx b/src/components/application-loader/application-loader.tsx index 711ea4f71..828cf5ab8 100644 --- a/src/components/application-loader/application-loader.tsx +++ b/src/components/application-loader/application-loader.tsx @@ -14,7 +14,13 @@ import { ApplicationLoaderError } from './application-loader-error' const log = new Logger('ApplicationLoader') -export const ApplicationLoader: React.FC> = ({ children }) => { +/** + * Initializes the application and executes all the setup tasks. + * It renders a {@link LoadingScreen} while this is happening. If there are any error, they will be displayed in the {@link LoadingScreen}. + * + * @param children The children in the React dom that should be shown once the application is loaded. + */ +export const ApplicationLoader: React.FC = ({ children }) => { const { error, loading } = useAsync(async () => { const initTasks = createSetUpTaskList() for (const task of initTasks) { diff --git a/src/components/application-loader/initializers/fetch-frontend-config.ts b/src/components/application-loader/initializers/fetch-frontend-config.ts index 5030cab39..e34ee2592 100644 --- a/src/components/application-loader/initializers/fetch-frontend-config.ts +++ b/src/components/application-loader/initializers/fetch-frontend-config.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -7,6 +7,9 @@ import { getConfig } from '../../../api/config' import { setConfig } from '../../../redux/config/methods' +/** + * Get the {@link Config frontend config} and save it in the global application state. + */ export const fetchFrontendConfig = async (): Promise => { const config = await getConfig() if (!config) { diff --git a/src/components/application-loader/initializers/index.ts b/src/components/application-loader/initializers/index.ts index 327c9f1bd..5d12b1b5c 100644 --- a/src/components/application-loader/initializers/index.ts +++ b/src/components/application-loader/initializers/index.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -12,6 +12,9 @@ import { fetchFrontendConfig } from './fetch-frontend-config' import { loadDarkMode } from './load-dark-mode' import { isDevMode, isTestMode } from '../../../utils/test-modes' +/** + * Create a custom delay in the loading of the application. + */ const customDelay: () => Promise = async () => { if ( (isDevMode || isTestMode) && @@ -30,6 +33,9 @@ export interface InitTask { task: () => Promise } +/** + * Create a list of tasks, that need to be fulfilled on startup. + */ export const createSetUpTaskList = (): InitTask[] => { return [ { diff --git a/src/components/application-loader/initializers/load-dark-mode.ts b/src/components/application-loader/initializers/load-dark-mode.ts index 7647d4681..24033fe50 100644 --- a/src/components/application-loader/initializers/load-dark-mode.ts +++ b/src/components/application-loader/initializers/load-dark-mode.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -31,7 +31,8 @@ export const loadDarkMode = async (): Promise => { /** * Tries to read the saved dark mode settings from the browser local storage. * - * @return {@code true} if the local storage has saved that the user prefers dark mode. {@code false} if the user doesn't or if the value could be read from local storage. + * @return {@link true} if the local storage has saved that the user prefers dark mode. + * {@link false} if the user doesn't prefer dark mode or if the value couldn't be read from local storage. */ const fetchDarkModeFromLocalStorage = (): boolean => { if (!isClientSideRendering()) { @@ -48,7 +49,9 @@ const fetchDarkModeFromLocalStorage = (): boolean => { /** * Tries to read the preferred dark mode setting from the browser settings. * - * @return {@code true} if the browser has reported that the user prefers dark mode. {@code false} if the user doesn't or if the browser doesn't support the `prefers-color-scheme` media query. + * @return {@link true} if the browser has reported that the user prefers dark mode. + * {@link false} if the browser doesn't prefer dark mode. + * {@link undefined} if the browser doesn't support the `prefers-color-scheme` media query. */ const determineDarkModeBrowserSettings = (): DarkModeConfig | undefined => { if (!isClientSideRendering()) { diff --git a/src/components/application-loader/initializers/setupI18n.ts b/src/components/application-loader/initializers/setupI18n.ts index 836db2ba3..7a3e0b621 100644 --- a/src/components/application-loader/initializers/setupI18n.ts +++ b/src/components/application-loader/initializers/setupI18n.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -12,6 +12,9 @@ import { Settings } from 'luxon' import { initReactI18next } from 'react-i18next' import { isDevMode } from '../../../utils/test-modes' +/** + * Set up the internationalisation framework i18n. + */ export const setUpI18n = async (): Promise => { await i18nUse( resourcesToBackend((language, namespace, callback) => { diff --git a/src/components/common/branding/branding.tsx b/src/components/common/branding/branding.tsx index da8e8a5e0..587871bd0 100644 --- a/src/components/common/branding/branding.tsx +++ b/src/components/common/branding/branding.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -14,6 +14,13 @@ export interface BrandingProps { delimiter?: boolean } +/** + * Show the branding of the HedgeDoc instance. + * This branding can either be a text, a logo or both (in that case the text is used as the title and alt of the image). + * + * @param inline If the logo should be using the inline-size or the regular-size css class. + * @param delimiter If the delimiter between the HedgeDoc logo and the branding should be shown. + */ export const Branding: React.FC = ({ inline = false, delimiter = true }) => { const branding = useApplicationState((state) => state.config.branding) const showBranding = !!branding.name || !!branding.logo diff --git a/src/components/common/cache/cache.test.ts b/src/components/common/cache/cache.test.ts deleted file mode 100644 index 34e7b9082..000000000 --- a/src/components/common/cache/cache.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) - * - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { Cache } from './cache' - -describe('Test caching functionality', () => { - let testCache: Cache - - beforeAll(() => { - jest.useFakeTimers() - }) - - afterAll(() => { - jest.useRealTimers() - }) - - beforeEach(() => { - testCache = new Cache(1000) - }) - - it('initialize with right lifetime, no entry limit', () => { - const lifetime = 1000 - const lifetimedCache = new Cache(lifetime) - expect(lifetimedCache.entryLifetime).toEqual(lifetime) - expect(lifetimedCache.maxEntries).toEqual(0) - }) - - it('initialize with right lifetime, given entry limit', () => { - const lifetime = 1000 - const maxEntries = 10 - const limitedCache = new Cache(lifetime, maxEntries) - expect(limitedCache.entryLifetime).toEqual(lifetime) - expect(limitedCache.maxEntries).toEqual(maxEntries) - }) - - it('entry exists after inserting', () => { - testCache.put('test', 123) - expect(testCache.has('test')).toBe(true) - }) - - it('entry does not exist prior inserting', () => { - expect(testCache.has('test')).toBe(false) - }) - - it('entry does expire', () => { - const shortLivingCache = new Cache(2) - shortLivingCache.put('test', 123) - expect(shortLivingCache.has('test')).toBe(true) - setTimeout(() => { - expect(shortLivingCache.has('test')).toBe(false) - }, 2000) - }) - - it('entry value does not change', () => { - const testValue = Date.now() - testCache.put('test', testValue) - expect(testCache.get('test')).toEqual(testValue) - }) - - it('error is thrown on non-existent entry', () => { - const accessNonExistentEntry = () => { - testCache.get('test') - } - expect(accessNonExistentEntry).toThrow(Error) - }) - - it('newer item replaces older item', () => { - testCache.put('test', 123) - testCache.put('test', 456) - expect(testCache.get('test')).toEqual(456) - }) - - it('entry limit is respected', () => { - const limitedCache = new Cache(1000, 2) - limitedCache.put('first', 1) - expect(limitedCache.has('first')).toBe(true) - expect(limitedCache.has('second')).toBe(false) - expect(limitedCache.has('third')).toBe(false) - limitedCache.put('second', 2) - expect(limitedCache.has('first')).toBe(true) - expect(limitedCache.has('second')).toBe(true) - expect(limitedCache.has('third')).toBe(false) - limitedCache.put('third', 3) - expect(limitedCache.has('first')).toBe(false) - expect(limitedCache.has('second')).toBe(true) - expect(limitedCache.has('third')).toBe(true) - }) -}) diff --git a/src/components/common/cache/cache.ts b/src/components/common/cache/cache.ts deleted file mode 100644 index 0d7ae4084..000000000 --- a/src/components/common/cache/cache.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) - * - * SPDX-License-Identifier: AGPL-3.0-only - */ - -export interface CacheEntry { - entryCreated: number - data: T -} - -export class Cache { - readonly entryLifetime: number - readonly maxEntries: number - private store = new Map>() - - constructor(lifetime: number, maxEntries = 0) { - if (lifetime < 0) { - throw new Error('Cache entry lifetime can not be less than 0 seconds.') - } - this.entryLifetime = lifetime - this.maxEntries = maxEntries - } - - has(key: K): boolean { - if (!this.store.has(key)) { - return false - } - const entry = this.store.get(key) - return !!entry && entry.entryCreated >= Date.now() - this.entryLifetime * 1000 - } - - get(key: K): V { - const entry = this.store.get(key) - if (!entry) { - throw new Error('This cache entry does not exist. Check with ".has()" before using ".get()".') - } - return entry.data - } - - put(key: K, value: V): void { - if (this.maxEntries > 0 && this.store.size === this.maxEntries) { - this.store.delete(this.store.keys().next().value as K) - } - this.store.set(key, { - entryCreated: Date.now(), - data: value - }) - } -} diff --git a/src/components/common/copyable/copyable-field/copyable-field.tsx b/src/components/common/copyable/copyable-field/copyable-field.tsx index 49d4a6281..c81426c5b 100644 --- a/src/components/common/copyable/copyable-field/copyable-field.tsx +++ b/src/components/common/copyable/copyable-field/copyable-field.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -21,7 +21,7 @@ export interface CopyableFieldProps { const log = new Logger('CopyableField') /** - * Provides an input field with an attached copy button and a share button (if supported by the browser) + * Provides an input field with an attached copy button and a share button (if supported by the browser). * * @param content The content to present * @param shareOriginUrl The URL of the page to which the shared content should be linked. If this value is omitted then the share button won't be shown. diff --git a/src/components/common/countdown-button/countdown-button.tsx b/src/components/common/countdown-button/countdown-button.tsx index 711d2d983..6e80c562a 100644 --- a/src/components/common/countdown-button/countdown-button.tsx +++ b/src/components/common/countdown-button/countdown-button.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -15,7 +15,10 @@ export interface CountdownButtonProps extends ButtonProps { /** * Button that starts a countdown on render and is only clickable after the countdown has finished. + * * @param countdownStartSeconds The initial amount of seconds for the countdown. + * @param children The children that should be displayed after the countdown has elapsed. + * @param props Additional props given to the {@link Button}. */ export const CountdownButton: React.FC = ({ countdownStartSeconds, children, ...props }) => { const [secondsRemaining, setSecondsRemaining] = useState(countdownStartSeconds) diff --git a/src/components/common/download/download.ts b/src/components/common/download/download.ts index 7ea49cf6e..13eb40129 100644 --- a/src/components/common/download/download.ts +++ b/src/components/common/download/download.ts @@ -1,15 +1,22 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ +/** + * Download a given {@link BlobPart file} from memory<. + * + * @param data The file to download. + * @param fileName Which filename does the file have. + * @param mimeType What is the files mimetype. + */ export const download = (data: BlobPart, fileName: string, mimeType: string): void => { const file = new Blob([data], { type: mimeType }) downloadLink(URL.createObjectURL(file), fileName) } -export const downloadLink = (url: string, fileName: string): void => { +const downloadLink = (url: string, fileName: string): void => { const helperElement = document.createElement('a') helperElement.href = url helperElement.download = fileName diff --git a/src/components/common/fields/current-password-field.tsx b/src/components/common/fields/current-password-field.tsx index 0f6065f01..8d4a0ba7d 100644 --- a/src/components/common/fields/current-password-field.tsx +++ b/src/components/common/fields/current-password-field.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -11,6 +11,7 @@ import { Trans, useTranslation } from 'react-i18next' /** * Renders an input field for the current password when changing passwords. + * * @param onChange Hook that is called when the entered password changes. */ export const CurrentPasswordField: React.FC = ({ onChange }) => { diff --git a/src/components/common/fields/display-name-field.tsx b/src/components/common/fields/display-name-field.tsx index ee3078b82..d59c3be33 100644 --- a/src/components/common/fields/display-name-field.tsx +++ b/src/components/common/fields/display-name-field.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -15,6 +15,7 @@ interface DisplayNameFieldProps extends CommonFieldProps { /** * Renders an input field for the display name when registering. + * * @param onChange Hook that is called when the entered display name changes. * @param value The currently entered display name. * @param initialValue The initial input field value. diff --git a/src/components/common/fields/new-password-field.tsx b/src/components/common/fields/new-password-field.tsx index 6b584df92..911c46077 100644 --- a/src/components/common/fields/new-password-field.tsx +++ b/src/components/common/fields/new-password-field.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -11,6 +11,7 @@ import { Trans, useTranslation } from 'react-i18next' /** * Renders an input field for the new password when registering. + * * @param onChange Hook that is called when the entered password changes. * @param value The currently entered password. */ diff --git a/src/components/common/fields/password-again-field.tsx b/src/components/common/fields/password-again-field.tsx index 5e1d32e11..2e4e33068 100644 --- a/src/components/common/fields/password-again-field.tsx +++ b/src/components/common/fields/password-again-field.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -15,6 +15,7 @@ interface PasswordAgainFieldProps extends CommonFieldProps { /** * Renders an input field for typing the new password again when registering. + * * @param onChange Hook that is called when the entered retype of the password changes. * @param value The currently entered retype of the password. * @param password The password entered into the password input field. diff --git a/src/components/common/fields/username-field.tsx b/src/components/common/fields/username-field.tsx index fa37be8c7..22c50123d 100644 --- a/src/components/common/fields/username-field.tsx +++ b/src/components/common/fields/username-field.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -11,6 +11,7 @@ import { Trans, useTranslation } from 'react-i18next' /** * Renders an input field for the username when registering. + * * @param onChange Hook that is called when the entered username changes. * @param value The currently entered username. */ diff --git a/src/components/common/fork-awesome/fork-awesome-icon.tsx b/src/components/common/fork-awesome/fork-awesome-icon.tsx index 027cf289a..c37f602a3 100644 --- a/src/components/common/fork-awesome/fork-awesome-icon.tsx +++ b/src/components/common/fork-awesome/fork-awesome-icon.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -15,6 +15,16 @@ export interface ForkAwesomeIconProps { stacked?: boolean } +/** + * Renders a fork awesome icon. + * + * @param icon The icon that should be rendered. + * @param fixedWidth If the icon should be rendered with a fixed width. + * @param size The size class the icon should be rendered in. + * @param className Additional classes the icon should get. + * @param stacked If the icon is part of a {@link ForkAwesomeStack stack}. + * @see https://forkaweso.me + */ export const ForkAwesomeIcon: React.FC = ({ icon, fixedWidth = false, diff --git a/src/components/common/fork-awesome/fork-awesome-stack.tsx b/src/components/common/fork-awesome/fork-awesome-stack.tsx index 20a1cee27..499b17359 100644 --- a/src/components/common/fork-awesome/fork-awesome-stack.tsx +++ b/src/components/common/fork-awesome/fork-awesome-stack.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -15,6 +15,12 @@ export interface ForkAwesomeStackProps { children: ReactElement | Array> } +/** + * A stack of {@link ForkAwesomeIcon ForkAwesomeIcons}. + * + * @param size Which size the stack should have. + * @param children One or more {@link ForkAwesomeIcon ForkAwesomeIcons} to be stacked. + */ export const ForkAwesomeStack: React.FC = ({ size, children }) => { return ( diff --git a/src/components/common/hedge-doc-logo/hedge-doc-logo-with-text.tsx b/src/components/common/hedge-doc-logo/hedge-doc-logo-with-text.tsx index 0daa1626a..a6df499cf 100644 --- a/src/components/common/hedge-doc-logo/hedge-doc-logo-with-text.tsx +++ b/src/components/common/hedge-doc-logo/hedge-doc-logo-with-text.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -27,6 +27,12 @@ export enum HedgeDocLogoType { WB_HORIZONTAL } +/** + * Renders the HedgeDoc logo with the app name in different types. + * + * @param size The size the logo should have. + * @param logoType The logo type to be used. + */ export const HedgeDocLogoWithText: React.FC = ({ size = HedgeDocLogoSize.MEDIUM, logoType }) => { const { t } = useTranslation() const altText = useMemo(() => t('app.icon'), [t]) diff --git a/src/components/common/icon-button/icon-button.tsx b/src/components/common/icon-button/icon-button.tsx index a240391ef..770eee249 100644 --- a/src/components/common/icon-button/icon-button.tsx +++ b/src/components/common/icon-button/icon-button.tsx @@ -20,6 +20,16 @@ export interface IconButtonProps extends ButtonProps { iconFixedWidth?: boolean } +/** + * A generic {@link Button button} with an {@link ForkAwesomeIcon icon} in it. + * + * @param icon Which icon should be used + * @param children The children that will be added as the content of the button. + * @param iconFixedWidth If the icon should be of fixed width. + * @param border Should the button have a border. + * @param className Additional class names added to the button. + * @param props Additional props for the button. + */ export const IconButton: React.FC = ({ icon, children, diff --git a/src/components/common/icon-button/translated-icon-button.tsx b/src/components/common/icon-button/translated-icon-button.tsx index 3e5b3c1f5..62a71f80b 100644 --- a/src/components/common/icon-button/translated-icon-button.tsx +++ b/src/components/common/icon-button/translated-icon-button.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -13,6 +13,12 @@ export interface TranslatedIconButtonProps extends IconButtonProps { i18nKey: string } +/** + * Renders an {@link IconButton icon button} with a translation inside. + * + * @param i18nKey The key for the translated string. + * @param props Additional props directly given to the {@link IconButton}. + */ export const TranslatedIconButton: React.FC = ({ i18nKey, ...props }) => { return ( diff --git a/src/components/common/links/external-link.tsx b/src/components/common/links/external-link.tsx index 5eb6eedfe..6bfb1ccf0 100644 --- a/src/components/common/links/external-link.tsx +++ b/src/components/common/links/external-link.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -10,6 +10,18 @@ import type { IconName } from '../fork-awesome/types' import { ShowIf } from '../show-if/show-if' import type { LinkWithTextProps } from './types' +/** + * An external link. + * This should be used for linking pages that are not part of the HedgeDoc instance. + * The links will be opened in a new tab. + * + * @param href The links location + * @param text The links text + * @param icon An optional icon to be shown before the links text + * @param id An id for the link object + * @param className Additional class names added to the link object + * @param title The title of the link + */ export const ExternalLink: React.FC = ({ href, text, diff --git a/src/components/common/links/internal-link.tsx b/src/components/common/links/internal-link.tsx index 4f40298e0..f7378209f 100644 --- a/src/components/common/links/internal-link.tsx +++ b/src/components/common/links/internal-link.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -11,6 +11,17 @@ import type { IconName } from '../fork-awesome/types' import { ShowIf } from '../show-if/show-if' import type { LinkWithTextProps } from './types' +/** + * An internal link. + * This should be used for linking pages of the HedgeDoc instance. + * + * @param href The links location + * @param text The links text + * @param icon An optional icon to be shown before the links text + * @param id An id for the link object + * @param className Additional class names added to the link object + * @param title The title of the link + */ export const InternalLink: React.FC = ({ href, text, diff --git a/src/components/common/links/translated-external-link.tsx b/src/components/common/links/translated-external-link.tsx index 3c7ba9c3d..099d37a36 100644 --- a/src/components/common/links/translated-external-link.tsx +++ b/src/components/common/links/translated-external-link.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -9,6 +9,13 @@ import { useTranslation } from 'react-i18next' import { ExternalLink } from './external-link' import type { TranslatedLinkProps } from './types' +/** + * An {@link ExternalLink external link} with translated text. + * + * @param i18nKey The key of the translation + * @param i18nOption The translation options + * @param props Additional props directly given to the {@link ExternalLink} + */ export const TranslatedExternalLink: React.FC = ({ i18nKey, i18nOption, ...props }) => { const { t } = useTranslation() return diff --git a/src/components/common/links/translated-internal-link.tsx b/src/components/common/links/translated-internal-link.tsx index cd8156cdd..79e7083e2 100644 --- a/src/components/common/links/translated-internal-link.tsx +++ b/src/components/common/links/translated-internal-link.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -8,7 +8,13 @@ import React from 'react' import { useTranslation } from 'react-i18next' import { InternalLink } from './internal-link' import type { TranslatedLinkProps } from './types' - +/** + * An {@link InternalLink internal link} with translated text. + * + * @param i18nKey The key of the translation + * @param i18nOption The translation options + * @param props Additional props directly given to the {@link InternalLink} + */ export const TranslatedInternalLink: React.FC = ({ i18nKey, i18nOption, ...props }) => { const { t } = useTranslation() return diff --git a/src/components/common/lock-button/lock-button.tsx b/src/components/common/lock-button/lock-button.tsx index 70113eb94..116ecb632 100644 --- a/src/components/common/lock-button/lock-button.tsx +++ b/src/components/common/lock-button/lock-button.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -14,6 +14,13 @@ export interface LockButtonProps { title: string } +/** + * A button with a lock icon. + * + * @param locked If the button should be shown as locked or not + * @param onLockedChanged The callback to change the state from locked to unlocked and vise-versa. + * @param title The title for the button. + */ export const LockButton: React.FC = ({ locked, onLockedChanged, title }) => { return (