From ecffebc43ca98a65d875f0d9d98057a1b582ffa7 Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Thu, 21 Jul 2022 22:36:46 +0200 Subject: [PATCH] docs: consolidate docs (#2182) Signed-off-by: Philip Molares --- src/api/alias/index.ts | 6 ++ src/api/auth/index.ts | 3 +- src/api/auth/ldap.ts | 4 +- src/api/auth/local.ts | 4 + .../api-request-builder-with-body.ts | 2 +- .../api-request-builder.ts | 2 +- .../delete-api-request-builder.ts | 4 +- .../get-api-request-builder.ts | 4 +- .../post-api-request-builder.ts | 4 +- .../put-api-request-builder.ts | 4 +- .../test-utils/expect-fetch.ts | 12 ++- src/api/common/api-response.ts | 3 +- src/api/config/index.ts | 2 + src/api/group/index.ts | 2 + src/api/history/dto-methods.ts | 18 +++- src/api/history/index.ts | 10 ++ src/api/me/index.ts | 9 +- src/api/media/index.ts | 6 ++ src/api/notes/index.ts | 10 ++ src/api/permissions/index.ts | 16 +++- src/api/revisions/index.ts | 6 ++ src/api/tokens/index.ts | 6 ++ src/api/users/index.ts | 2 + .../application-loader-error.ts | 5 +- .../application-loader/application-loader.tsx | 8 +- .../initializers/fetch-frontend-config.ts | 5 +- .../application-loader/initializers/index.ts | 8 +- .../initializers/load-dark-mode.ts | 9 +- .../initializers/setupI18n.ts | 5 +- src/components/common/branding/branding.tsx | 9 +- src/components/common/cache/cache.test.ts | 91 ------------------- src/components/common/cache/cache.ts | 50 ---------- .../copyable-field/copyable-field.tsx | 4 +- .../countdown-button/countdown-button.tsx | 5 +- src/components/common/download/download.ts | 11 ++- .../common/fields/current-password-field.tsx | 3 +- .../common/fields/display-name-field.tsx | 3 +- .../common/fields/new-password-field.tsx | 3 +- .../common/fields/password-again-field.tsx | 3 +- .../common/fields/username-field.tsx | 3 +- .../common/fork-awesome/fork-awesome-icon.tsx | 12 ++- .../fork-awesome/fork-awesome-stack.tsx | 8 +- .../hedge-doc-logo-with-text.tsx | 8 +- .../common/icon-button/icon-button.tsx | 10 ++ .../icon-button/translated-icon-button.tsx | 8 +- src/components/common/links/external-link.tsx | 14 ++- src/components/common/links/internal-link.tsx | 13 ++- .../common/links/translated-external-link.tsx | 9 +- .../common/links/translated-internal-link.tsx | 10 +- .../common/lock-button/lock-button.tsx | 9 +- src/components/common/modals/common-modal.tsx | 16 +++- .../common/modals/deletion-modal.tsx | 15 ++- .../common/number-range/number-range.ts | 8 +- .../common/pagination/pager-item.tsx | 8 +- .../common/pagination/pager-pagination.tsx | 9 +- src/components/common/pagination/pager.tsx | 10 +- src/components/common/show-if/show-if.tsx | 8 +- .../user-avatar/user-avatar-for-username.tsx | 3 +- .../common/wait-spinner/wait-spinner.tsx | 5 +- .../document-infobar.tsx | 4 +- .../editor-page/app-bar/app-bar.tsx | 7 +- .../editor-page/app-bar/dark-mode-button.tsx | 5 +- .../editor-page/app-bar/editor-view-mode.tsx | 4 + .../app-bar/help-button/cheatsheet-line.tsx | 9 +- .../help-button/cheatsheet-tab-content.tsx | 5 +- .../app-bar/help-button/help-button.tsx | 3 + .../app-bar/help-button/help-modal.tsx | 13 ++- .../app-bar/help-button/links-tab-content.tsx | 5 +- .../help-button/shortcuts-tab-content.tsx | 5 +- .../editor-page/app-bar/navbar-branding.tsx | 5 +- .../editor-page/app-bar/new-note-button.tsx | 3 + .../sync-scroll-buttons.tsx | 6 +- .../change-content-context.tsx | 8 +- .../note-info/note-info-line-created.tsx | 1 + .../note-info/note-info-line-updated.tsx | 1 + .../document-bar/note-info/note-info-line.tsx | 10 +- .../note-info/note-info-modal.tsx | 1 + .../document-bar/note-info/time-from-now.tsx | 7 +- .../note-info/unitalic-bold-content.tsx | 6 +- .../permission-add-entry-field.tsx | 1 + .../permissions/permission-entry-buttons.tsx | 1 + .../permission-entry-special-group.tsx | 1 + .../permissions/permission-entry-user.tsx | 1 + .../permissions/permission-modal.tsx | 3 +- .../permissions/permission-owner-change.tsx | 5 + .../permissions/permission-owner-info.tsx | 1 + .../revisions/revision-modal-footer.tsx | 1 + .../document-bar/revisions/utils.ts | 4 +- .../document-bar/share/share-modal.tsx | 6 ++ .../editor-page/editor-pane/editor-pane.tsx | 9 ++ .../hooks/table-paste/codefenceDetection.ts | 2 +- .../hooks/table-paste/table-extractor.ts | 5 +- .../hooks/use-apply-scroll-state.ts | 1 - .../hooks/use-cursor-activity-callback.ts | 2 +- .../editor-pane/hooks/use-handle-upload.tsx | 2 +- .../hooks/use-line-based-position.ts | 4 +- .../hooks/yjs/use-bind-y-text-to-redux.ts | 2 +- .../hooks/yjs/use-is-connection-synced.ts | 1 + .../use-on-first-editor-update-extension.ts | 2 +- .../hooks/yjs/websocket-connection.ts | 2 +- .../number-of-lines-in-document-info.tsx | 4 +- .../status-bar/remaining-characters-info.tsx | 5 +- .../tool-bar/buttons/bold-button.tsx | 3 + .../tool-bar/buttons/check-list-button.tsx | 3 + .../tool-bar/buttons/code-fence-button.tsx | 3 + .../buttons/collapsible-block-button.tsx | 3 + .../tool-bar/buttons/comment-button.tsx | 3 + .../tool-bar/buttons/header-level-button.tsx | 3 + .../tool-bar/buttons/highlight-button.tsx | 3 + .../buttons/horizontal-line-button.tsx | 3 + .../tool-bar/buttons/image-link-button.tsx | 3 + .../tool-bar/buttons/italic-button.tsx | 3 + .../tool-bar/buttons/link-button.tsx | 3 + .../tool-bar/buttons/ordered-list-button.tsx | 3 + .../tool-bar/buttons/quotes-button.tsx | 3 + .../tool-bar/buttons/strikethrough-button.tsx | 3 + .../tool-bar/buttons/subscript-button.tsx | 3 + .../tool-bar/buttons/superscript-button.tsx | 3 + .../tool-bar/buttons/underline-button.tsx | 3 + .../buttons/unordered-list-button.tsx | 3 + .../emoji-picker/emoji-picker-button.tsx | 4 + .../tool-bar/emoji-picker/emoji-picker.tsx | 28 ++++-- .../tool-bar/formatters/add-link.ts | 4 +- .../formatters/prepend-lines-of-selection.ts | 4 +- .../tool-bar/formatters/replace-selection.ts | 5 +- ...e-cursors-to-whole-line-if-no-to-cursor.ts | 6 +- .../tool-bar/formatters/wrap-selection.ts | 8 +- .../table-picker/create-markdown-table.tsx | 2 +- .../table-size-picker-popover.tsx | 10 +- .../editor-pane/tool-bar/tool-bar.tsx | 3 + .../extract-selected-text.ts | 2 +- .../upload-image-button.tsx | 2 +- .../editor-page/hooks/useEditorModeFromUrl.ts | 5 +- .../hooks/useUpdateLocalHistoryEntry.ts | 6 +- .../editor-page/hooks/useViewModeShortcuts.ts | 7 +- .../render-context/use-origin-from-config.ts | 4 +- .../communicator-image-lightbox.tsx | 3 + ...render-page-url-on-iframe-load-callback.ts | 4 +- .../hooks/use-send-scroll-state.ts | 3 +- .../renderer-pane/render-iframe.tsx | 17 +++- .../yaml-array-deprecation-alert.tsx | 7 +- .../delete-note-sidebar-entry.tsx | 2 +- .../sidebar/sidebar-button/sidebar-button.tsx | 3 +- .../sidebar/sidebar-menu/sidebar-menu.tsx | 8 +- .../editor-page/sidebar/sidebar.tsx | 5 +- .../export-menu-sidebar-menu.tsx | 10 +- .../import-markdown-sidebar-entry.tsx | 5 +- .../import-menu-sidebar-menu.tsx | 10 +- .../note-info-sidebar-entry.tsx | 6 ++ .../permissions-sidebar-entry.tsx | 6 ++ .../pin-note-sidebar-entry.tsx | 8 +- .../revision-sidebar-entry.tsx | 6 ++ .../share-sidebar-entry.tsx | 6 ++ .../editor-page/sidebar/upload-input.tsx | 16 +++- .../sidebar/user-line/user-line.tsx | 1 + .../active-indicator.tsx | 5 + .../users-online-sidebar-menu.tsx | 9 ++ .../splitter/split-divider/split-divider.tsx | 8 +- .../editor-page/splitter/splitter.tsx | 15 +-- .../editor-page/synced-scroll/utils.ts | 10 +- .../build-react-dom-from-toc-ast.tsx | 11 ++- .../table-of-contents/table-of-contents.tsx | 10 +- .../table-of-contents/toc-slugify.ts | 9 +- src/components/editor-page/utils.ts | 6 +- .../error-boundary/error-boundary.tsx | 7 +- .../entry-menu/delete-note-item.tsx | 8 +- .../dropdown-item-with-deletion-modal.tsx | 2 +- .../history-page/entry-menu/entry-menu.tsx | 3 +- .../entry-menu/remove-note-entry-item.tsx | 8 +- .../history-card/history-card-list.tsx | 3 +- .../history-card/history-card.tsx | 3 +- .../history-table/history-table-row.tsx | 3 +- .../history-table/history-table.tsx | 3 +- .../history-toolbar/clear-history-button.tsx | 4 + .../history-toolbar/export-history-button.tsx | 5 +- .../history-toolbar/toolbar-filter-props.d.ts | 12 --- .../history-page/pin-button/pin-button.tsx | 10 +- .../history-page/sort-button/sort-button.tsx | 22 ++++- .../history-page/use-history-entry-title.ts | 3 +- src/components/history-page/utils.ts | 8 +- src/components/intro-page/requests.ts | 6 ++ .../landing-layout/footer/footer.tsx | 5 +- .../landing-layout/footer/language-picker.tsx | 8 +- .../footer/powered-by-links.tsx | 5 +- .../landing-layout/footer/social-links.tsx | 5 +- .../footer/version-info/version-info-link.tsx | 3 + .../version-info-modal-column.tsx | 11 ++- .../version-info/version-info-modal.tsx | 8 +- .../landing-layout/landing-layout.tsx | 7 +- .../navigation/header-bar/header-bar.tsx | 5 +- .../navigation/new-guest-note-button.tsx | 5 +- .../navigation/new-user-note-button.tsx | 5 +- .../navigation/sign-in-button.tsx | 6 +- .../navigation/user-dropdown.tsx | 5 +- .../login-page/auth/auth-error/auth-error.tsx | 5 +- .../login-page/auth/fields/password-field.tsx | 3 +- .../login-page/auth/fields/username-field.tsx | 3 +- .../social-link-button/social-link-button.tsx | 11 ++- src/components/login-page/auth/utils.ts | 5 +- .../utils/get-one-click-provider-metadata.ts | 1 + .../login-page/auth/via-one-click.tsx | 3 +- .../document-markdown-renderer.tsx | 17 +++- .../use-convert-markdown-to-react-dom.ts | 4 +- .../hooks/use-on-ref-change.ts | 8 +- .../markdown-renderer/hooks/use-reveal.ts | 11 ++- .../markdown-renderer/invalid-yaml-alert.tsx | 7 +- .../markdown-extension/abcjs/abc-frame.tsx | 8 +- .../alert-markdown-extension.ts | 5 +- ...ockquote-border-color-node-preprocessor.ts | 13 ++- ...blockquote-extra-tag-markdown-it-plugin.ts | 2 + .../blockquote-extra-tag-replacer.tsx | 2 +- .../markdown-extension/csv/csv-parser.ts | 3 +- .../markdown-extension/csv/csv-table.tsx | 11 ++- .../debugger-markdown-extension.ts | 5 +- .../flowchart/flowchart.tsx | 6 ++ .../generic-syntax-markdown-extension.ts | 5 +- .../gist/replace-gist-link.ts | 5 +- .../gist/replace-legacy-gist-short-code.ts | 5 +- .../gist/use-resize-gist-frame.ts | 9 +- .../graphviz/graphviz-frame.tsx | 9 +- .../headline-anchors-markdown-extension.ts | 5 +- .../highlighted-fence/highlighted-code.tsx | 3 +- .../image-placeholder-markdown-extension.ts | 4 +- .../image/image-lightbox-modal.tsx | 11 ++- .../image/proxy-image-frame.tsx | 10 +- .../katex/katex-markdown-extension.ts | 4 +- .../katex/katex-replacer.tsx | 6 +- .../replace-legacy-pdf-short-code.ts | 7 +- .../replace-legacy-slideshare-short-code.ts | 7 +- .../replace-legacy-speakerdeck-short-code.ts | 7 +- .../link-replacer/anchor-node-preprocessor.ts | 5 +- .../link-replacer/jump-anchor.tsx | 9 +- .../linkify-fix-markdown-extension.ts | 5 +- .../markdown-extension/markdown-extension.ts | 5 +- .../markmap/markmap-frame.tsx | 8 +- .../markmap/markmap-loader.ts | 8 +- .../mermaid/mermaid-chart.tsx | 8 +- .../plantuml/plantuml-markdown-extension.ts | 7 +- .../plantuml-not-configured-alert.tsx | 5 +- ...tuml-not-configured-component-replacer.tsx | 5 +- .../reveal/process-reveal-comment-nodes.ts | 5 +- .../dom-purifier-node-preprocessor.ts | 4 +- .../sequence-diagram/deprecation-warning.tsx | 5 +- .../spoiler-markdown-extension.ts | 14 ++- .../table-of-contents-markdown-extension.ts | 6 +- .../vega-lite/vega-lite-chart.tsx | 8 +- .../vimeo/replace-legacy-vimeo-short-code.ts | 7 +- .../vimeo/replace-vimeo-link.ts | 5 +- .../replace-legacy-youtube-short-code.ts | 7 +- .../youtube/replace-youtube-link.ts | 5 +- .../node-preprocessors/node-processor.ts | 5 +- .../traveler-node-processor.ts | 5 +- .../replace-components/component-replacer.ts | 4 +- .../slideshow-markdown-renderer.tsx | 17 +++- .../test-utils/test-markdown-renderer.tsx | 6 ++ .../utils/calculate-line-marker-positions.ts | 12 ++- .../markdown-renderer/utils/line-id-mapper.ts | 6 +- .../utils/node-to-react-transformer.tsx | 1 + .../notifications/ui-notification-toast.tsx | 16 +++- .../notifications/ui-notifications.tsx | 5 +- .../access-token-created-modal.tsx | 3 +- ...ccess-token-creation-form-expiry-field.tsx | 3 +- ...access-token-creation-form-label-field.tsx | 3 +- .../access-token-creation-form.tsx | 3 +- .../hooks/use-expiry-dates.ts | 3 +- .../hooks/use-on-create-token.ts | 3 +- .../access-token-deletion-modal.tsx | 3 +- .../access-tokens/access-token-list-entry.tsx | 1 + .../account-deletion-modal.tsx | 3 +- .../register-error/register-error.tsx | 5 +- .../use-document-sync-scrolling.ts | 14 ++- .../hooks/sync-scroll/use-on-user-scroll.ts | 10 +- .../sync-scroll/use-scroll-to-line-mark.ts | 10 +- .../hooks/use-image-click-handler.ts | 8 +- .../render-page/iframe-markdown-renderer.tsx | 5 +- .../render-page/markdown-document.tsx | 20 +++- .../table-of-contents-hovering-button.tsx | 3 +- .../width-based-table-of-contents.tsx | 3 +- .../hooks/use-is-renderer-ready.ts | 6 +- .../hooks/use-send-to-renderer.ts | 7 +- .../window-post-message-communicator.ts | 4 +- src/components/render-page/word-counter.ts | 11 ++- .../slide-show-page-content.tsx | 5 +- .../respond-to-matching-request.ts | 2 +- src/hooks/common/use-app-title.ts | 6 +- src/hooks/common/use-application-state.ts | 3 +- src/hooks/common/use-apply-dark-mode.ts | 5 +- .../common/use-array-string-url-parameter.ts | 8 +- ...e-bind-pointer-movement-event-on-window.ts | 2 +- src/hooks/common/use-frontend-base-url.ts | 7 +- .../common/use-is-dark-mode-activated.ts | 7 +- src/hooks/common/use-note-markdown-content.ts | 5 +- src/hooks/common/use-note-title.ts | 6 +- src/hooks/common/use-on-input-change.ts | 3 +- .../common/use-single-string-url-parameter.ts | 9 +- ...te-markdown-content-without-frontmatter.ts | 4 +- src/pages/404.tsx | 2 +- src/pages/p/[noteId].tsx | 5 +- .../build-state-from-first-heading-update.ts | 2 +- ...build-state-from-update-cursor-position.ts | 4 +- src/utils/api-url.ts | 3 + src/utils/customize-assets-url.ts | 3 + src/utils/cypress-attribute.ts | 4 +- src/utils/is-client-side-rendering.ts | 5 +- src/utils/is-positive-answer.ts | 3 +- src/utils/logger.ts | 16 ++-- src/utils/read-file.ts | 2 +- 307 files changed, 1474 insertions(+), 487 deletions(-) delete mode 100644 src/components/common/cache/cache.test.ts delete mode 100644 src/components/common/cache/cache.ts delete mode 100644 src/components/history-page/history-toolbar/toolbar-filter-props.d.ts 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 (