From 485474cf1da61d076d5b955183de0c4ebc3e9445 Mon Sep 17 00:00:00 2001 From: ajnart Date: Sun, 30 Aug 2026 13:32:46 +0200 Subject: [PATCH] chore: prepare v2 release --- .cursor/rules/codebase-context.mdc | 2 +- .github/ISSUE_TEMPLATE/bug_report.yml | 4 + .../extract-build-artifact/action.yaml | 2 +- .github/actions/prebuilt-debian/action.yaml | 3 - .github/workflows/autofix.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/deployment-docker-image.yml | 23 +- .../on-pr-prebuilt-debian-validate.yml | 2 +- .github/workflows/on-pr-renovate-validate.yml | 2 +- .github/workflows/update-contributors.yml | 7 +- .github/workflows/workshop.yml | 17 + CHANGELOG.md | 8 + MANTINE.md | 475 ------------------ .../advanced/environment-variables/index.mdx | 20 + .../docs/getting-started/installation/helm.md | 6 +- .../custom-widgets/agent-authoring.mdx | 57 --- .../docs/management/custom-widgets/index.mdx | 56 +-- .../docs/management/search-engines/index.mdx | 2 +- apps/docs/docs/widgets/assistant/index.mdx | 53 +- apps/docs/docs/widgets/timer/index.mdx | 29 +- apps/docs/docs/workshop/operator.mdx | 16 - apps/workshop/README.md | 211 ++------ package.json | 2 +- 23 files changed, 147 insertions(+), 854 deletions(-) delete mode 100644 MANTINE.md diff --git a/.cursor/rules/codebase-context.mdc b/.cursor/rules/codebase-context.mdc index 349673637..418e281c6 100644 --- a/.cursor/rules/codebase-context.mdc +++ b/.cursor/rules/codebase-context.mdc @@ -23,7 +23,7 @@ Homarr is an open-source, self-hosted dashboard for managing homelab services. I - **Testing**: Vitest + jsdom, Playwright for E2E - **Lint/Format**: oxlint + oxfmt (not ESLint/Prettier) - **Docs**: Docusaurus 3 in `apps/docs/` (`@homarr/docs`) -- **Package manager**: pnpm 10.34.1, Node >= 24.16.0 +- **Package manager**: pnpm 11.15.1, Node >= 24.18.0 ## Repository Structure diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index d4b730726..da7634ca6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -33,6 +33,10 @@ body: options: # The below comment is used to insert a new version with on-release.yml #NEXT_VERSION# + - 1.76.2 + - 1.76.1 + - 1.76.0 + - 1.75.0 - 1.74.0 - 1.73.0 - 1.72.0 diff --git a/.github/actions/extract-build-artifact/action.yaml b/.github/actions/extract-build-artifact/action.yaml index 4751c9029..2f0c66c34 100644 --- a/.github/actions/extract-build-artifact/action.yaml +++ b/.github/actions/extract-build-artifact/action.yaml @@ -20,7 +20,7 @@ runs: using: "composite" steps: - name: Prebuilt debian dependencies - uses: homarr-labs/homarr/.github/actions/prebuilt-debian@dev + uses: ./.github/actions/prebuilt-debian id: prebuilt-debian with: architecture: ${{ inputs.architecture }} diff --git a/.github/actions/prebuilt-debian/action.yaml b/.github/actions/prebuilt-debian/action.yaml index 6e8b04846..4860fa4b7 100644 --- a/.github/actions/prebuilt-debian/action.yaml +++ b/.github/actions/prebuilt-debian/action.yaml @@ -11,9 +11,6 @@ outputs: runs: using: "composite" steps: - - uses: actions/checkout@v7 - with: - persist-credentials: false - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 733e21eb9..0e0fae81c 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -3,7 +3,7 @@ name: Formatting on: pull_request: types: [opened, synchronize, reopened] - branches: ["*"] + branches: ["**"] permissions: contents: read diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39d2c4904..551ad055d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -436,7 +436,7 @@ jobs: const targetTags = target.metadata?.container?.tags ?? []; const extraTags = targetTags.filter((targetTag) => targetTag !== tag); if (extraTags.length > 0) { - core.setFailed( + core.warning( `Package version ${target.id} also carries tag(s) ${extraTags.map((targetTag) => `"${targetTag}"`).join(", ")}; refusing cleanup.`, ); return; diff --git a/.github/workflows/deployment-docker-image.yml b/.github/workflows/deployment-docker-image.yml index 9ea0c2a09..486dcb617 100644 --- a/.github/workflows/deployment-docker-image.yml +++ b/.github/workflows/deployment-docker-image.yml @@ -58,8 +58,9 @@ jobs: permission-contents: write # required to commit package.json & changelog changes, merge them to dev / next and publish the release - uses: actions/checkout@v7 - if: env.SKIP_RELEASE == 'false' + if: env.SKIP_RELEASE == 'false' || github.ref_name == 'main' || github.ref_name == 'beta' with: + fetch-depth: 0 persist-credentials: false - uses: pnpm/action-setup@v6 if: env.SKIP_RELEASE == 'false' @@ -68,12 +69,9 @@ jobs: with: node-version: 24.18.0 package-manager-cache: false - - run: npm i -g pnpm - if: env.SKIP_RELEASE == 'false' - name: Install dependencies if: env.SKIP_RELEASE == 'false' - run: | - pnpm install + run: pnpm install --frozen-lockfile - name: Run Semantic Release if: env.SKIP_RELEASE == 'false' env: @@ -205,9 +203,14 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: + - uses: actions/checkout@v7 + if: needs.release.outputs.skipped == 'false' + with: + ref: ${{ needs.release.outputs.git_ref }} + persist-credentials: false - name: Extract amd64 if: needs.release.outputs.skipped == 'false' - uses: homarr-labs/homarr/.github/actions/extract-build-artifact@dev + uses: ./.github/actions/extract-build-artifact with: digest: "${{ env.GHCR_REPO }}@${{ needs.build-amd64.outputs.digest }}" architecture: amd64 @@ -221,9 +224,14 @@ jobs: runs-on: ubuntu-24.04-arm timeout-minutes: 5 steps: + - uses: actions/checkout@v7 + if: needs.release.outputs.skipped == 'false' + with: + ref: ${{ needs.release.outputs.git_ref }} + persist-credentials: false - name: Extract arm64 if: needs.release.outputs.skipped == 'false' - uses: homarr-labs/homarr/.github/actions/extract-build-artifact@dev + uses: ./.github/actions/extract-build-artifact with: digest: "${{ env.GHCR_REPO }}@${{ needs.build-arm64.outputs.digest }}" architecture: arm64 @@ -284,6 +292,7 @@ jobs: gh release edit --repo ${{ github.repository }} ${{ needs.release.outputs.version }} --draft=false - name: Discord notification + if: github.event_name != 'workflow_dispatch' || inputs['send-notifications'] env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} uses: Ilshidur/action-discord@0.4.0 diff --git a/.github/workflows/on-pr-prebuilt-debian-validate.yml b/.github/workflows/on-pr-prebuilt-debian-validate.yml index a67dd1d62..2f049ed38 100644 --- a/.github/workflows/on-pr-prebuilt-debian-validate.yml +++ b/.github/workflows/on-pr-prebuilt-debian-validate.yml @@ -5,7 +5,7 @@ permissions: on: pull_request: - branches: ["*"] + branches: ["**"] paths: [".github/actions/prebuilt-debian/**", "deployments/prebuilt-debian/**"] jobs: diff --git a/.github/workflows/on-pr-renovate-validate.yml b/.github/workflows/on-pr-renovate-validate.yml index 4a77b1175..52e234708 100644 --- a/.github/workflows/on-pr-renovate-validate.yml +++ b/.github/workflows/on-pr-renovate-validate.yml @@ -5,7 +5,7 @@ permissions: on: pull_request: - branches: ["*"] + branches: ["**"] paths: [".github/renovate.json5"] jobs: diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml index bb4364596..c185e0527 100644 --- a/.github/workflows/update-contributors.yml +++ b/.github/workflows/update-contributors.yml @@ -15,9 +15,6 @@ jobs: update-contributors: runs-on: ubuntu-latest timeout-minutes: 2 - strategy: - matrix: - node-version: [22] steps: - name: Obtain token id: obtainToken @@ -34,10 +31,10 @@ jobs: GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }} - uses: pnpm/action-setup@v6 - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js uses: actions/setup-node@v6 with: - node-version: ${{ matrix.node-version }} + node-version: 24.18.0 cache: "pnpm" - name: Run update script diff --git a/.github/workflows/workshop.yml b/.github/workflows/workshop.yml index 3fec8610d..88bfecd47 100644 --- a/.github/workflows/workshop.yml +++ b/.github/workflows/workshop.yml @@ -8,6 +8,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ (github.ref_name == 'v2' || github.ref_name == 'release/v2') && 'v2-preview' || github.ref }} + cancel-in-progress: true + jobs: validate: runs-on: ubuntu-24.04 @@ -102,6 +106,19 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Verify branch head before publication + uses: actions/github-script@v8 + with: + script: | + const branchName = context.ref.replace("refs/heads/", ""); + const { data: branch } = await github.rest.repos.getBranch({ + owner: context.repo.owner, + repo: context.repo.repo, + branch: branchName, + }); + if (branch.commit.sha !== context.sha) { + core.setFailed(`Branch ${branchName} moved from ${context.sha} to ${branch.commit.sha}.`); + } - name: Publish multi-platform image env: AMD64_DIGEST: ${{ needs.publish-amd64.outputs.digest }} diff --git a/CHANGELOG.md b/CHANGELOG.md index a829e2042..a2ea18e53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## [1.76.2](https://github.com/homarr-labs/homarr/compare/v1.76.1...v1.76.2) (2026-08-27) + +## [1.76.1](https://github.com/homarr-labs/homarr/compare/v1.76.0...v1.76.1) (2026-08-26) + +## [1.76.0](https://github.com/homarr-labs/homarr/compare/v1.75.0...v1.76.0) (2026-08-21) + +## [1.75.0](https://github.com/homarr-labs/homarr/compare/v1.74.0...v1.75.0) (2026-08-14) + ## [1.74.0](https://github.com/homarr-labs/homarr/compare/v1.73.0...v1.74.0) (2026-08-07) ## [1.73.0](https://github.com/homarr-labs/homarr/compare/v1.72.0...v1.73.0) (2026-07-31) diff --git a/MANTINE.md b/MANTINE.md deleted file mode 100644 index c60cc8e3b..000000000 --- a/MANTINE.md +++ /dev/null @@ -1,475 +0,0 @@ -# Mantine UI - LLM Documentation - -This index lists Mantine documentation pages formatted for LLMs. -Each link points to a standalone Markdown file under the /llms path. - -For a single consolidated file with all content, use: - -- https://mantine.dev/llms-full.txt - -## FAQ - -- [Are Mantine components accessible?](https://mantine.dev/llms/q-are-mantine-components-accessible.md): Learn about Mantine components accessibility features -- [Browser zooms in when input is focused. What should I do?](https://mantine.dev/llms/q-browser-zooms-on-focus.md): Use meta tag to disable browser scaling or increase input size -- [Can I have color schemes other than light and dark?](https://mantine.dev/llms/q-light-dark-is-not-enough.md): Learn about the difference between color scheme and theme -- [Can I have different primary color for light and dark color schemes?](https://mantine.dev/llms/q-primary-virtual-color.md): Learn how to use virtual color with primary color in theme object -- [Can I remove MultiSelect placeholder when the component has selected values?](https://mantine.dev/llms/q-multiselect-value-placeholder.md): Learn why MultiSelect placeholder is not removed when values are selected and how to remove it with CSS -- [Can I use an array of strings as a list in use-form?](https://mantine.dev/llms/q-list-of-strings-in-use-form.md): Learn about use-form lists limitations -- [Can I use Mantine components as server components?](https://mantine.dev/llms/q-server-components.md): Learn about use client directive and server components usage -- [Can I use Mantine with Astro?](https://mantine.dev/llms/q-can-i-use-mantine-with-astro.md): No, Astro does not support React context -- [Can I use Mantine with Create React App (CRA)?](https://mantine.dev/llms/q-can-i-use-mantine-with-cra.md): Learn how to use Mantine without postcss-preset-mantine or how to eject CRA and customize webpack.config.js and use postcss-preset-mantine -- [Can I use Mantine with Emotion/styled-components/tailwindcss?](https://mantine.dev/llms/q-third-party-styles.md): Learn about limitations of third-party styles -- [Can I use Mantine with Vue/Svelte/Angular/etc.?](https://mantine.dev/llms/q-vue-svelte-angular.md): No, Mantine is a React library and does not support other frameworks/libraries -- [Can I use nested inline styles with Mantine components?](https://mantine.dev/llms/q-nested-inline-styles.md): Nested styles are supported only in CSS files -- [Can I use PostCSS function in inline styles?](https://mantine.dev/llms/q-postcss-fns-inline.md): Learn where PostCSS functions can be used in Mantine -- [Can I use private CSS variables to style components?](https://mantine.dev/llms/q-private-css-variables.md): No, it is not safe and will not work with future versions of Mantine. -- [Can I use SegmentedControl with empty value?](https://mantine.dev/llms/q-segmented-control-no-value.md): SegmentedControl cannot be used without a value -- [How can I add dynamic CSS styles?](https://mantine.dev/llms/q-dynamic-css-styles.md): Use data attributes, CSS variables or inline styles -- [How can I add fuzzy search to Select component?](https://mantine.dev/llms/q-select-fuzzy.md): Learn how to integrate third-party fuzzy search libraries with Mantine Select component -- [How can I add hover styles to an element?](https://mantine.dev/llms/q-how-to-add-hover-styles.md): Learn how to add hover classes to an element with CSS modules, &:hover or @mixin hover -- [How can I apply styles to all Mantine components?](https://mantine.dev/llms/q-apply-styles-to-all.md): Learn how to use attribute selector to apply styles to all Mantine components -- [How can I change body background color?](https://mantine.dev/llms/q-body-background.md): Use CSS to change body background color -- [How can I change component color prop value depending on the color scheme?](https://mantine.dev/llms/q-color-scheme-color.md): Learn how to use CSS variables resolver to change color value depending on the color scheme -- [How can I change input focus styles?](https://mantine.dev/llms/q-input-focus-styles.md): Learn how to use Styles API with Mantine inputs -- [How can I change Tabs border color?](https://mantine.dev/llms/q-tabs-border-color.md): Learn how to use Styles API with Tabs component -- [How can I contribute to the library?](https://mantine.dev/llms/q-how-can-i-contribute.md): There are multiple ways to contribute even without writing code -- [How can I disable all inputs/input groups inside a form?](https://mantine.dev/llms/q-disable-all-inputs-in-form.md): Learn how to disable all inputs/input groups inside a form with the unstyled Fieldset component -- [How can I display different elements in light and dark color schemes?](https://mantine.dev/llms/q-light-dark-elements.md): Learn how to hide/show elements based on color scheme -- [How can I focus the first input with error with use-form?](https://mantine.dev/llms/q-focus-first-input-with-error.md): Learn how to handle focus with use-form hook -- [How can I get current color scheme value in JavaScript?](https://mantine.dev/llms/q-how-to-get-color-scheme-value-in-js.md): How to use useMantineColorScheme and useComputedColorScheme hooks to get current color scheme value in JavaScript -- [How can I lint CSS files?](https://mantine.dev/llms/q-how-to-setup-stylelint.md): Learn how to set up Stylelint for Mantine postcss syntax -- [How can I load fonts in Next.js?](https://mantine.dev/llms/q-next-load-fonts.md): A guide to load custom fonts in Next.js with CSS and next/font package -- [How can I load fonts in React Router?](https://mantine.dev/llms/q-react-router-load-fonts.md): A guide to load custom fonts in React Router -- [How can I load fonts in Vite?](https://mantine.dev/llms/q-vite-load-fonts.md): A guide to load custom fonts in Vite -- [How can I lock scroll in my application?](https://mantine.dev/llms/q-how-to-lock-scroll.md): Use react-remove-scroll library to lock scroll in your application -- [How can I submit a template to Mantine documentation?](https://mantine.dev/llms/q-submit-template.md): Learn how to create and submit a template to Mantine documentation -- [How can I test Modal/Drawer/Popover components?](https://mantine.dev/llms/q-portals-testing.md): Learn how to use react-testing-library to test components that use portals and transitions. -- [How can I test Select/MultiSelect components?](https://mantine.dev/llms/q-combobox-testing.md): Learn how to use react-testing-library to test Select and MultiSelect components. -- [How can I upload files from Dropzone component?](https://mantine.dev/llms/q-dropzone-upload.md): Learn how to process files dropped into Dropzone component -- [How is that thing done on the mantine.dev website?](https://mantine.dev/llms/q-how-that-thing-is-done.md): Learn how various elements are implemented on the mantine.dev website -- [How to align input with a button in a flex container?](https://mantine.dev/llms/q-align-input-button.md): Learn how to align Mantine inputs with buttons using Group component -- [How to call a function when Modal/Drawer closes and animation completes?](https://mantine.dev/llms/q-how-to-call-function-when-modal-closes.md): How to use transitionProps in Modal/Drawer components -- [How to change background color for FiveM?](https://mantine.dev/llms/q-fivem-background-color.md): Unset body background color and color-scheme styles for FiveM -- [How to change input placeholder color?](https://mantine.dev/llms/q-inputs-placeholder-color.md): Learn how to change placeholder color with Styles API -- [How to integrate custom input with use-form hook?](https://mantine.dev/llms/q-custom-input-use-form.md): Learn how to add use-form support for custom inputs -- [How to prevent Modal from closing?](https://mantine.dev/llms/q-how-to-prevent-modal-from-closing.md): Learn how to prevent Modal from closing when the user clicks outside of it or presses the Escape key -- [How to scroll to the top of the form if the form is submitted with errors?](https://mantine.dev/llms/q-scroll-to-the-top-of-the-form.md): Learn how to call a function when the form is submitted with errors -- [How to update Mantine dependencies?](https://mantine.dev/llms/q-how-to-update-dependencies.md): Learn how to update `@mantine/*`, `@mantinex/*` and `postcss-preset-mantine` dependencies manually or with ncu script -- [How to use Dropzone with @mantine/form?](https://mantine.dev/llms/q-how-to-use-dropzone-with-form.md): Learn how to use Dropzone with @mantine/form to handle file selection state -- [How to use Mantine template on GitHub?](https://mantine.dev/llms/q-templates-usage.md): Learn how to create a new repository based on Mantine template -- [I get hydration warning about data-mantine-color-scheme attribute, what does it mean?](https://mantine.dev/llms/q-color-scheme-hydration-warning.md): Learn how hydration works and how to fix warnings -- [Is there a comparison with other libraries?](https://mantine.dev/llms/q-other-libs.md): Comparison with other libraries is not provided, you are trusted to make your own decision based on documentation examples -- [Is there a floating action button component?](https://mantine.dev/llms/q-floating-action-button.md): No, but you can build it with Affix and ActionIcon components -- [Is there DataGrid component that I can use with Mantine?](https://mantine.dev/llms/q-data-grid-i-need.md): A list of community packages that provide DataGrid component that can be used with Mantine. -- [It is not possible to pinch to zoom when a Modal is opened. What should I do?](https://mantine.dev/llms/q-pinch-to-zoom-modal.md): Use removeScrollProps to configure react-remove-scroll options -- [MantineProvider was not found in component tree. What should I do?](https://mantine.dev/llms/q-mantine-provider-missing.md): Learn how to resolve MantineProvider issues -- [My buttons are transparent and the background is visible only on hover, what is wrong?](https://mantine.dev/llms/q-transparent-buttons.md): You have installed a third-party library that overrides Mantine styles -- [My Popover dropdown closes when I click on the dropdown of a nested Popover](https://mantine.dev/llms/q-nested-popover-closes.md): Popover dropdown is closed when it detects click-outside events -- [My styles are broken with disabled JavaScript. What should I do?](https://mantine.dev/llms/q-disabled-js.md): Learn how to use Mantine without JavaScript enabled -- [My styles are overridden by Mantine components styles, what should I do?](https://mantine.dev/llms/q-styles-order.md): Learn how to use CSS layers to control styles order and prevent Mantine components from overriding your styles -- [Native browser validation does not work in some components, what should I do?](https://mantine.dev/llms/q-native-required.md): Learn why native browser validation does not work in some components -- [The use-local-storage hook returns the real value only after mounting. Is it a bug?](https://mantine.dev/llms/q-local-storage-effect.md): Learn how Mantine retrieves local storage value -- [What is the difference between searchable Select and Autocomplete?](https://mantine.dev/llms/q-select-autocomplete-difference.md): Searchable Select and Autocomplete are similar components, but they serve different purposes. -- [Where can I find the roadmap?](https://mantine.dev/llms/q-roadmap.md): The roadmap is private and only available to the team. -- [Why are my Carousel slides in vertical orientation?](https://mantine.dev/llms/q-carousel-missing-styles.md): You forgot to import carousel styles -- [Why are my notifications displayed at the wrong position?](https://mantine.dev/llms/q-notifications-missing-styles.md): Because you did not import styles -- [Why can I not use one polymorphic component in the component prop of another polymorphic component?](https://mantine.dev/llms/q-polymorphic-in-polymorphic.md): Learn how polymorphic components types work -- [Why can I not use value/label data structure with Autocomplete/TagsInput?](https://mantine.dev/llms/q-autocomplete-value-label.md): Learn the difference between Autocomplete and Select components -- [Why can VSCode not autoimport the Text component?](https://mantine.dev/llms/q-why-vscode-cannot-autoimport-text.md): It is confused by the native Text constructor -- [Why do I see color scheme flickering on page load?](https://mantine.dev/llms/q-color-scheme-flickering.md): Color scheme flickering is caused by incorrect usage of ColorSchemeScript -- [Why do my dates components look broken?](https://mantine.dev/llms/q-dates-missing-styles.md): Because you did not import styles -- [Why does FileButton not work in Menu?](https://mantine.dev/llms/q-file-button-in-menu.md): Learn how to use FileButton in Menu component -- [Why is it required to have 10 shades per color?](https://mantine.dev/llms/q-ten-shades-per-color.md): Learn how Mantine uses theme colors -- [Why is my screen completely empty after I](https://mantine.dev/llms/q-notifications-empty-screen.md): You have used Notifications component incorrectly - -## Core - -- [Accordion](https://mantine.dev/llms/core-accordion.md): Divide content into collapsible sections -- [ActionIcon](https://mantine.dev/llms/core-action-icon.md): Icon button -- [Affix](https://mantine.dev/llms/core-affix.md): Renders children inside portal at fixed position -- [Alert](https://mantine.dev/llms/core-alert.md): Attract user attention with important static message -- [AlphaSlider](https://mantine.dev/llms/core-alpha-slider.md): Slider component for selecting alpha channel in color pickers (0 – 1) -- [Anchor](https://mantine.dev/llms/core-anchor.md): Display link with theme styles -- [AngleSlider](https://mantine.dev/llms/core-angle-slider.md): Pick angle value between 0 and 360 -- [AppShell](https://mantine.dev/llms/core-app-shell.md): Responsive shell for your application with header, navbar, aside and footer -- [AspectRatio](https://mantine.dev/llms/core-aspect-ratio.md): Maintain responsive consistent width/height ratio -- [Autocomplete](https://mantine.dev/llms/core-autocomplete.md): Autocomplete user input with any list of options -- [Avatar](https://mantine.dev/llms/core-avatar.md): Display user profile image, initials or fallback icon -- [BackgroundImage](https://mantine.dev/llms/core-background-image.md): Displays image as background -- [Badge](https://mantine.dev/llms/core-badge.md): Display badge, pill or tag -- [Blockquote](https://mantine.dev/llms/core-blockquote.md): Blockquote with optional cite -- [Box](https://mantine.dev/llms/core-box.md): Base component for all Mantine components -- [Breadcrumbs](https://mantine.dev/llms/core-breadcrumbs.md): Separates list of react nodes with given separator -- [Burger](https://mantine.dev/llms/core-burger.md): Open/close navigation button -- [Button](https://mantine.dev/llms/core-button.md): Button component to render button or link -- [Card](https://mantine.dev/llms/core-card.md): Card with sections -- [Cascader](https://mantine.dev/llms/core-cascader.md): Select a path from hierarchical data with cascading columns -- [Center](https://mantine.dev/llms/core-center.md): Centers content vertically and horizontally -- [Checkbox](https://mantine.dev/llms/core-checkbox.md): Capture boolean input from user -- [Chip](https://mantine.dev/llms/core-chip.md): Pick one or multiple values with inline controls -- [CloseButton](https://mantine.dev/llms/core-close-button.md): Button with close icon -- [Code](https://mantine.dev/llms/core-code.md): Inline and block code -- [Collapse](https://mantine.dev/llms/core-collapse.md): Animate presence with slide down/up transition -- [ColorInput](https://mantine.dev/llms/core-color-input.md): Capture color from user -- [ColorPicker](https://mantine.dev/llms/core-color-picker.md): Pick colors in hex(a), rgb(a), hsl(a) and hsv(a) formats -- [ColorSwatch](https://mantine.dev/llms/core-color-swatch.md): Displays color -- [Combobox](https://mantine.dev/llms/core-combobox.md): Create custom select, autocomplete or multiselect inputs -- [ComboboxPopover](https://mantine.dev/llms/core-combobox-popover.md): Add combobox dropdown to any button element -- [Container](https://mantine.dev/llms/core-container.md): Center content with padding and max-width -- [CopyButton](https://mantine.dev/llms/core-copy-button.md): Copies given text to clipboard -- [CorePackage](https://mantine.dev/llms/core-package.md) -- [DataList](https://mantine.dev/llms/core-data-list.md): Display label-value pairs as a description list -- [Dialog](https://mantine.dev/llms/core-dialog.md): Display a fixed overlay dialog at any side of the screen -- [Divider](https://mantine.dev/llms/core-divider.md): Horizontal line with optional label or vertical divider -- [Drawer](https://mantine.dev/llms/core-drawer.md): Display overlay area at any side of the screen -- [EmptyState](https://mantine.dev/llms/core-empty-state.md): Display a placeholder for no data, empty results and first-run states -- [Fieldset](https://mantine.dev/llms/core-fieldset.md): Group related elements in a form -- [FileButton](https://mantine.dev/llms/core-file-button.md): Open file picker with a button click -- [FileInput](https://mantine.dev/llms/core-file-input.md): Capture files from user -- [Flex](https://mantine.dev/llms/core-flex.md): Compose elements in a flex container -- [FloatingIndicator](https://mantine.dev/llms/core-floating-indicator.md): Display a floating indicator over a group of elements -- [FloatingWindow](https://mantine.dev/llms/core-floating-window.md): Draggable floating area -- [FocusTrap](https://mantine.dev/llms/core-focus-trap.md): Trap focus at child node -- [Grid](https://mantine.dev/llms/core-grid.md): Responsive 12 columns grid system -- [Group](https://mantine.dev/llms/core-group.md): Compose elements and components in a horizontal flex container -- [Highlight](https://mantine.dev/llms/core-highlight.md): Highlight given part of a string with mark -- [HoverCard](https://mantine.dev/llms/core-hover-card.md): Display popover section when target element is hovered -- [HueSlider](https://mantine.dev/llms/core-hue-slider.md): Slider component for selecting hue channel in color pickers (0 – 360 degrees) -- [Image](https://mantine.dev/llms/core-image.md): Image with optional fallback -- [Indicator](https://mantine.dev/llms/core-indicator.md): Display element at the corner of another element -- [Input](https://mantine.dev/llms/core-input.md): Base component to create custom inputs -- [JsonInput](https://mantine.dev/llms/core-json-input.md): Capture json data from user -- [Kbd](https://mantine.dev/llms/core-kbd.md): Display keyboard key -- [List](https://mantine.dev/llms/core-list.md): Display ordered or unordered list -- [Loader](https://mantine.dev/llms/core-loader.md): Indicate loading state -- [LoadingOverlay](https://mantine.dev/llms/core-loading-overlay.md): An overlay with centered loader -- [Mark](https://mantine.dev/llms/core-mark.md): Highlight part of the text -- [Marquee](https://mantine.dev/llms/core-marquee.md): Create continuous scrolling animation for content -- [MaskInput](https://mantine.dev/llms/core-mask-input.md): Input with mask pattern for formatted text entry -- [Menu](https://mantine.dev/llms/core-menu.md): Combine a list of secondary actions into single interactive area -- [Menubar](https://mantine.dev/llms/core-menubar.md): Desktop application style menubar with a row of menu triggers -- [Modal](https://mantine.dev/llms/core-modal.md): An accessible overlay dialog -- [MultiSelect](https://mantine.dev/llms/core-multi-select.md): Custom searchable multi select -- [NativeSelect](https://mantine.dev/llms/core-native-select.md): Native select element based on Input -- [NavLink](https://mantine.dev/llms/core-nav-link.md): Navigation link -- [Notification](https://mantine.dev/llms/core-notification.md): Show dynamic notifications and alerts to user, part of notifications system -- [NumberFormatter](https://mantine.dev/llms/core-number-formatter.md): Format number with thousands/decimal separators and suffix/prefix -- [NumberInput](https://mantine.dev/llms/core-number-input.md): Capture number from user -- [OverflowList](https://mantine.dev/llms/core-overflow-list.md): Hide items that do not fit in a container and display them as a single collapsed item -- [Overlay](https://mantine.dev/llms/core-overlay.md): Overlays parent element with div element with any color and opacity -- [Pagination](https://mantine.dev/llms/core-pagination.md): Display active page and navigate between multiple pages -- [Paper](https://mantine.dev/llms/core-paper.md): Renders white or dark background depending on color scheme -- [PasswordInput](https://mantine.dev/llms/core-password-input.md): Capture password data from user -- [Pill](https://mantine.dev/llms/core-pill.md): Removable and non-removable tags -- [PillsInput](https://mantine.dev/llms/core-pills-input.md): Base component for custom tags inputs and multi selects -- [PinInput](https://mantine.dev/llms/core-pin-input.md): Capture pin code or one time password from the user -- [Popover](https://mantine.dev/llms/core-popover.md): Display popover section relative to given target element -- [Portal](https://mantine.dev/llms/core-portal.md): Renders component outside of parent element tree -- [Progress](https://mantine.dev/llms/core-progress.md): Give user feedback for status of the task -- [Radio](https://mantine.dev/llms/core-radio.md): Wrapper for input type radio -- [RangeSlider](https://mantine.dev/llms/core-range-slider.md): RangeSlider component -- [Rating](https://mantine.dev/llms/core-rating.md): Pick and display rating -- [RingProgress](https://mantine.dev/llms/core-ring-progress.md): Give user feedback for status of the task with circle diagram -- [RollingNumber](https://mantine.dev/llms/core-rolling-number.md): Animate value changes with rolling digits -- [ScrollArea](https://mantine.dev/llms/core-scroll-area.md): Area with custom scrollbars -- [Scroller](https://mantine.dev/llms/core-scroller.md): Horizontal scroll container with navigation controls -- [SegmentedControl](https://mantine.dev/llms/core-segmented-control.md): A linear set of two or more segments -- [Select](https://mantine.dev/llms/core-select.md): Custom searchable select -- [SemiCircleProgress](https://mantine.dev/llms/core-semi-circle-progress.md): Represent progress with semi circle diagram -- [SimpleGrid](https://mantine.dev/llms/core-simple-grid.md): Responsive grid in which each item takes equal amount of space -- [Skeleton](https://mantine.dev/llms/core-skeleton.md): Indicate content loading state -- [Slider](https://mantine.dev/llms/core-slider.md): Slider component -- [Space](https://mantine.dev/llms/core-space.md): Add horizontal or vertical spacing from theme -- [Splitter](https://mantine.dev/llms/core-splitter.md): Resizable split pane layout -- [Spoiler](https://mantine.dev/llms/core-spoiler.md): Hide long sections of content under a spoiler -- [Stack](https://mantine.dev/llms/core-stack.md): Compose elements and components in a vertical flex container -- [Stepper](https://mantine.dev/llms/core-stepper.md): Display content divided into a steps sequence -- [Switch](https://mantine.dev/llms/core-switch.md): Capture boolean input from user -- [Table](https://mantine.dev/llms/core-table.md): Render table with theme styles -- [TableOfContents](https://mantine.dev/llms/core-table-of-contents.md): Renders a list of headings on the page and tracks current heading visible in the viewport -- [Tabs](https://mantine.dev/llms/core-tabs.md): Switch between different views -- [TagsInput](https://mantine.dev/llms/core-tags-input.md): Capture a list of values from user with free input and suggestions -- [Text](https://mantine.dev/llms/core-text.md): Display text -- [Textarea](https://mantine.dev/llms/core-textarea.md): Autosize or regular textarea -- [TextInput](https://mantine.dev/llms/core-text-input.md): Capture string input from user -- [ThemeIcon](https://mantine.dev/llms/core-theme-icon.md): Render icon inside element with theme colors -- [Timeline](https://mantine.dev/llms/core-timeline.md): Display list of events in chronological order -- [Title](https://mantine.dev/llms/core-title.md): h1-h6 heading -- [Tooltip](https://mantine.dev/llms/core-tooltip.md): Renders tooltip at given element on mouse over or other event -- [Transition](https://mantine.dev/llms/core-transition.md): Animate presence of component with pre-made animations -- [Tree](https://mantine.dev/llms/core-tree.md): Display a Tree structure -- [TreeSelect](https://mantine.dev/llms/core-tree-select.md): Select with hierarchical tree data -- [Typography](https://mantine.dev/llms/core-typography.md): Styles provider for html content -- [UnstyledButton](https://mantine.dev/llms/core-unstyled-button.md): Unstyled polymorphic button -- [VisuallyHidden](https://mantine.dev/llms/core-visually-hidden.md): Hide element visually but keep it accessible for screen readers - -## Hooks - -- [HooksPackage](https://mantine.dev/llms/hooks-package.md) -- [use-element-size](https://mantine.dev/llms/hooks-use-element-size.md): Returns element width and height and observes changes with ResizeObserver -- [useClickOutside](https://mantine.dev/llms/hooks-use-click-outside.md) -- [useClipboard](https://mantine.dev/llms/hooks-use-clipboard.md) -- [useCollapse](https://mantine.dev/llms/hooks-use-collapse.md) -- [useColorScheme](https://mantine.dev/llms/hooks-use-color-scheme.md) -- [useCounter](https://mantine.dev/llms/hooks-use-counter.md) -- [useDebouncedCallback](https://mantine.dev/llms/hooks-use-debounced-callback.md) -- [useDebouncedState](https://mantine.dev/llms/hooks-use-debounced-state.md) -- [useDebouncedValue](https://mantine.dev/llms/hooks-use-debounced-value.md) -- [useDidUpdate](https://mantine.dev/llms/hooks-use-did-update.md) -- [useDisclosure](https://mantine.dev/llms/hooks-use-disclosure.md) -- [useDocumentTitle](https://mantine.dev/llms/hooks-use-document-title.md) -- [useDocumentVisibility](https://mantine.dev/llms/hooks-use-document-visibility.md) -- [useDrag](https://mantine.dev/llms/hooks-use-drag.md) -- [useEventListener](https://mantine.dev/llms/hooks-use-event-listener.md) -- [useEyeDropper](https://mantine.dev/llms/hooks-use-eye-dropper.md) -- [useFavicon](https://mantine.dev/llms/hooks-use-favicon.md) -- [useFetch](https://mantine.dev/llms/hooks-use-fetch.md) -- [useFileDialog](https://mantine.dev/llms/hooks-use-file-dialog.md) -- [useFloatingWindow](https://mantine.dev/llms/hooks-use-floating-window.md) -- [useFocusReturn](https://mantine.dev/llms/hooks-use-focus-return.md) -- [useFocusTrap](https://mantine.dev/llms/hooks-use-focus-trap.md) -- [useFocusWithin](https://mantine.dev/llms/hooks-use-focus-within.md) -- [useForceUpdate](https://mantine.dev/llms/hooks-use-force-update.md) -- [useFullscreen](https://mantine.dev/llms/hooks-use-fullscreen.md) -- [useHash](https://mantine.dev/llms/hooks-use-hash.md) -- [useHeadroom](https://mantine.dev/llms/hooks-use-headroom.md) -- [useHotkeys](https://mantine.dev/llms/hooks-use-hotkeys.md) -- [useHover](https://mantine.dev/llms/hooks-use-hover.md) -- [useId](https://mantine.dev/llms/hooks-use-id.md) -- [useIdle](https://mantine.dev/llms/hooks-use-idle.md) -- [useInputState](https://mantine.dev/llms/hooks-use-input-state.md) -- [useIntersection](https://mantine.dev/llms/hooks-use-intersection.md) -- [useInterval](https://mantine.dev/llms/hooks-use-interval.md) -- [useInViewport](https://mantine.dev/llms/hooks-use-in-viewport.md) -- [useIsFirstRender](https://mantine.dev/llms/hooks-use-is-first-render.md) -- [useIsomorphicEffect](https://mantine.dev/llms/hooks-use-isomorphic-effect.md) -- [useListState](https://mantine.dev/llms/hooks-use-list-state.md) -- [useLocalStorage](https://mantine.dev/llms/hooks-use-local-storage.md) -- [useLogger](https://mantine.dev/llms/hooks-use-logger.md) -- [useLongPress](https://mantine.dev/llms/hooks-use-long-press.md) -- [useMap](https://mantine.dev/llms/hooks-use-map.md) -- [useMask](https://mantine.dev/llms/hooks-use-mask.md) -- [useMediaQuery](https://mantine.dev/llms/hooks-use-media-query.md) -- [useMergedRef](https://mantine.dev/llms/hooks-use-merged-ref.md) -- [useMounted](https://mantine.dev/llms/hooks-use-mounted.md) -- [useMouse](https://mantine.dev/llms/hooks-use-mouse.md) -- [useMove](https://mantine.dev/llms/hooks-use-move.md) -- [useMutationObserver](https://mantine.dev/llms/hooks-use-mutation-observer.md) -- [useNetwork](https://mantine.dev/llms/hooks-use-network.md) -- [useOrientation](https://mantine.dev/llms/hooks-use-orientation.md) -- [useOs](https://mantine.dev/llms/hooks-use-os.md) -- [usePageLeave](https://mantine.dev/llms/hooks-use-page-leave.md) -- [usePagination](https://mantine.dev/llms/hooks-use-pagination.md) -- [usePrevious](https://mantine.dev/llms/hooks-use-previous.md) -- [useQueue](https://mantine.dev/llms/hooks-use-queue.md) -- [useRadialMove](https://mantine.dev/llms/hooks-use-radial-move.md) -- [useReducedMotion](https://mantine.dev/llms/hooks-use-reduced-motion.md) -- [useResizeObserver](https://mantine.dev/llms/hooks-use-resize-observer.md) -- [useRovingIndex](https://mantine.dev/llms/hooks-use-roving-index.md) -- [useScrollDirection](https://mantine.dev/llms/hooks-use-scroll-direction.md) -- [useScroller](https://mantine.dev/llms/hooks-use-scroller.md) -- [useScrollIntoView](https://mantine.dev/llms/hooks-use-scroll-into-view.md) -- [useScrollSpy](https://mantine.dev/llms/hooks-use-scroll-spy.md) -- [useSelection](https://mantine.dev/llms/hooks-use-selection.md) -- [useSet](https://mantine.dev/llms/hooks-use-set.md) -- [useSetState](https://mantine.dev/llms/hooks-use-set-state.md) -- [useShallowEffect](https://mantine.dev/llms/hooks-use-shallow-effect.md) -- [useSplitter](https://mantine.dev/llms/hooks-use-splitter.md) -- [useStateHistory](https://mantine.dev/llms/hooks-use-state-history.md) -- [useTextSelection](https://mantine.dev/llms/hooks-use-text-selection.md) -- [useThrottledCallback](https://mantine.dev/llms/hooks-use-throttled-callback.md) -- [useThrottledState](https://mantine.dev/llms/hooks-use-throttled-state.md) -- [useThrottledValue](https://mantine.dev/llms/hooks-use-throttled-value.md) -- [useTimeout](https://mantine.dev/llms/hooks-use-timeout.md) -- [useToggle](https://mantine.dev/llms/hooks-use-toggle.md) -- [useUncontrolled](https://mantine.dev/llms/hooks-use-uncontrolled.md) -- [useValidatedState](https://mantine.dev/llms/hooks-use-validated-state.md) -- [useViewportSize](https://mantine.dev/llms/hooks-use-viewport-size.md) -- [useWindowEvent](https://mantine.dev/llms/hooks-use-window-event.md) -- [useWindowScroll](https://mantine.dev/llms/hooks-use-window-scroll.md) - -## Form - -- [Form context](https://mantine.dev/llms/form-create-form-context.md): Add context support to use-form with createFormContext -- [formActions](https://mantine.dev/llms/form-actions.md) -- [formAllInputs](https://mantine.dev/llms/form-all-inputs.md) -- [formErrors](https://mantine.dev/llms/form-errors.md) -- [formGetInputProps](https://mantine.dev/llms/form-get-input-props.md) -- [formNested](https://mantine.dev/llms/form-nested.md) -- [FormPackage](https://mantine.dev/llms/form-package.md) -- [formRecipes](https://mantine.dev/llms/form-recipes.md) -- [formSchemaValidation](https://mantine.dev/llms/form-schema-validation.md) -- [formStatus](https://mantine.dev/llms/form-status.md) -- [formUncontrolled](https://mantine.dev/llms/form-uncontrolled.md) -- [formValidation](https://mantine.dev/llms/form-validation.md) -- [formValidators](https://mantine.dev/llms/form-validators.md) -- [formValues](https://mantine.dev/llms/form-values.md) -- [use-field](https://mantine.dev/llms/form-use-field.md): use-field hook – manage single field state -- [use-form](https://mantine.dev/llms/form-use-form.md): Manage form state - -## Dates - -- [Calendar](https://mantine.dev/llms/dates-calendar.md): Base component for custom date pickers -- [DateInput](https://mantine.dev/llms/dates-date-input.md): Free form date input -- [DatePicker](https://mantine.dev/llms/dates-date-picker.md): Inline date, multiple dates and dates range picker -- [DatePickerInput](https://mantine.dev/llms/dates-date-picker-input.md): Date, multiple dates and dates range picker input -- [DateTimePicker](https://mantine.dev/llms/dates-date-time-picker.md): Capture datetime from the user -- [GettingStartedDates](https://mantine.dev/llms/dates-getting-started.md) -- [InlineDateTimePicker](https://mantine.dev/llms/dates-inline-date-time-picker.md): Inline date and time picker with range support -- [MiniCalendar](https://mantine.dev/llms/dates-mini-calendar.md): Compact calendar to display a small number of days in a row -- [MonthPicker](https://mantine.dev/llms/dates-month-picker.md): Inline month, multiple months and months range picker -- [MonthPickerInput](https://mantine.dev/llms/dates-month-picker-input.md): Month, multiple months and months range picker input -- [TimeGrid](https://mantine.dev/llms/dates-time-grid.md): Captures time value from the user with a predefined set of options -- [TimeInput](https://mantine.dev/llms/dates-time-input.md): Capture time from the user -- [TimePicker](https://mantine.dev/llms/dates-time-picker.md): Captures time value from the user -- [TimeValue](https://mantine.dev/llms/dates-time-value.md): Display a formatted time value -- [YearPicker](https://mantine.dev/llms/dates-year-picker.md): Inline year, multiple years and years range picker -- [YearPickerInput](https://mantine.dev/llms/dates-year-picker-input.md): Inline year, multiple years and years range picker - -## Charts - -- [AreaChart](https://mantine.dev/llms/charts-area-chart.md): Area chart component with stacked, percent and split variants -- [BarChart](https://mantine.dev/llms/charts-bar-chart.md): Bar chart component with stacked and percent variants -- [BarsList](https://mantine.dev/llms/charts-bars-list.md): Display a list of bars with names and values -- [BubbleChart](https://mantine.dev/llms/charts-bubble-chart.md): Bubble chart component -- [BulletChart](https://mantine.dev/llms/charts-bullet-chart.md): Compact KPI chart with value, target, and qualitative ranges -- [CompositeChart](https://mantine.dev/llms/charts-composite-chart.md): Composed chart with support for Area, Bar and Line charts -- [DonutChart](https://mantine.dev/llms/charts-donut-chart.md): Donut chart component -- [FunnelChart](https://mantine.dev/llms/charts-funnel-chart.md): Funnel chart component -- [GettingStartedCharts](https://mantine.dev/llms/charts-getting-started.md) -- [Heatmap](https://mantine.dev/llms/charts-heatmap.md): Heatmap chart component -- [LineChart](https://mantine.dev/llms/charts-line-chart.md): Line chart component -- [PieChart](https://mantine.dev/llms/charts-pie-chart.md): Pie chart component -- [RadarChart](https://mantine.dev/llms/charts-radar-chart.md): Radar chart component -- [RadialBarChart](https://mantine.dev/llms/charts-radial-bar-chart.md): Radial bar chart component -- [SankeyChart](https://mantine.dev/llms/charts-sankey-chart.md): Sankey diagram component -- [ScatterChart](https://mantine.dev/llms/charts-scatter-chart.md): Scatter chart component -- [Sparkline](https://mantine.dev/llms/charts-sparkline.md): Simplified area chart to show trends -- [SunburstChart](https://mantine.dev/llms/charts-sunburst-chart.md): Sunburst chart component for hierarchical data -- [Treemap](https://mantine.dev/llms/charts-treemap.md): Treemap chart component - -## Schedule - -- [AgendaView](https://mantine.dev/llms/schedule-agenda-view.md): Vertical list view of events grouped by date -- [DayView](https://mantine.dev/llms/schedule-day-view.md): Standalone schedule day view component -- [GettingStartedSchedule](https://mantine.dev/llms/schedule-getting-started.md) -- [MobileMonthView](https://mantine.dev/llms/schedule-mobile-month-view.md): Mobile-optimized schedule month view component -- [MonthView](https://mantine.dev/llms/schedule-month-view.md): Standalone schedule month view component -- [RecurringEventsSchedule](https://mantine.dev/llms/schedule-recurring-events.md) -- [ResourcesDayView](https://mantine.dev/llms/schedule-resources-day-view.md): Day view with resource columns for scheduling across resources -- [ResourcesMonthView](https://mantine.dev/llms/schedule-resources-month-view.md): Month view with resource lanes for scheduling across resources -- [ResourcesSchedule](https://mantine.dev/llms/schedule-resources-schedule.md): Schedule wrapper component that combines resource day, week and month views -- [ResourcesWeekView](https://mantine.dev/llms/schedule-resources-week-view.md): Week view with resource rows for scheduling across resources -- [Schedule](https://mantine.dev/llms/schedule-schedule.md): Schedule component with day, week, month and year views -- [ScheduleEventsData](https://mantine.dev/llms/schedule-events-data.md) -- [WeekView](https://mantine.dev/llms/schedule-week-view.md): Standalone schedule week view component -- [YearView](https://mantine.dev/llms/schedule-year-view.md): Standalone schedule year view component - -## Guides - -- [ControlledVsUncontrolled](https://mantine.dev/llms/guides-controlled-vs-uncontrolled.md) -- [CustomComponents](https://mantine.dev/llms/guides-custom-components.md) -- [EightToNine](https://mantine.dev/llms/guides-8x-to-9x.md) -- [FunctionsReference](https://mantine.dev/llms/guides-functions-reference.md) -- [Gatsby](https://mantine.dev/llms/guides-gatsby.md) -- [Icons](https://mantine.dev/llms/guides-icons.md) -- [JavaScript](https://mantine.dev/llms/guides-javascript.md) -- [Jest](https://mantine.dev/llms/guides-jest.md) -- [LLMDocumentation](https://mantine.dev/llms/guides-llms.md) -- [NextJs](https://mantine.dev/llms/guides-next.md) -- [Polymorphic](https://mantine.dev/llms/guides-polymorphic.md) -- [ReactRouter](https://mantine.dev/llms/guides-react-router.md) -- [Redwood](https://mantine.dev/llms/guides-redwood.md) -- [SevenToEight](https://mantine.dev/llms/guides-7x-to-8x.md) -- [SixToSeven](https://mantine.dev/llms/guides-6x-to-7x.md) -- [Storybook](https://mantine.dev/llms/guides-storybook.md) -- [Tiptap3Migration](https://mantine.dev/llms/guides-tiptap-3-migration.md) -- [TypeScript](https://mantine.dev/llms/guides-typescript.md) -- [Vite](https://mantine.dev/llms/guides-vite.md) -- [Vitest](https://mantine.dev/llms/guides-vitest.md) - -## Theming - -- [Colors](https://mantine.dev/llms/theming-colors.md) -- [ColorSchemes](https://mantine.dev/llms/theming-color-schemes.md) -- [DefaultProps](https://mantine.dev/llms/theming-default-props.md) -- [MantineProvider](https://mantine.dev/llms/theming-mantine-provider.md) -- [ThemeObject](https://mantine.dev/llms/theming-theme-object.md) -- [Typography](https://mantine.dev/llms/theming-typography.md): Styles provider for html content - -## Styles - -- [ColorFunctions](https://mantine.dev/llms/styles-color-functions.md) -- [CSSFilesList](https://mantine.dev/llms/styles-css-files-list.md) -- [CSSModules](https://mantine.dev/llms/styles-css-modules.md) -- [CssVariables](https://mantine.dev/llms/styles-css-variables.md) -- [CSSVariablesList](https://mantine.dev/llms/styles-css-variables-list.md) -- [DataAttributes](https://mantine.dev/llms/styles-data-attributes.md) -- [Emotion](https://mantine.dev/llms/styles-emotion.md) -- [GlobalStyles](https://mantine.dev/llms/styles-global-styles.md) -- [MantineStyles](https://mantine.dev/llms/styles-mantine-styles.md) -- [PostCSSPreset](https://mantine.dev/llms/styles-postcss-preset.md) -- [Rem](https://mantine.dev/llms/styles-rem.md) -- [ResponsiveStyles](https://mantine.dev/llms/styles-responsive.md) -- [Rtl](https://mantine.dev/llms/styles-rtl.md) -- [StyleProp](https://mantine.dev/llms/styles-style.md) -- [StyleProps](https://mantine.dev/llms/styles-style-props.md) -- [StylesApi](https://mantine.dev/llms/styles-styles-api.md) -- [StylesOverview](https://mantine.dev/llms/styles-styles-overview.md) -- [StylesPerformance](https://mantine.dev/llms/styles-styles-performance.md) -- [UnstyledComponents](https://mantine.dev/llms/styles-unstyled.md) -- [UsageWithSass](https://mantine.dev/llms/styles-sass.md) -- [VanillaExtract](https://mantine.dev/llms/styles-vanilla-extract.md) -- [VariantsAndSizes](https://mantine.dev/llms/styles-variants-sizes.md) - -## X - -- [Carousel](https://mantine.dev/llms/x-carousel.md): Embla based carousel component -- [CodeHighlight](https://mantine.dev/llms/x-code-highlight.md): Highlight code with shiki or highlight.js -- [Dropzone](https://mantine.dev/llms/x-dropzone.md): Capture files from user with drag and drop -- [ExtensionsPackage](https://mantine.dev/llms/x-extensions.md) -- [Modals manager](https://mantine.dev/llms/x-modals.md): Centralized modals manager with option to handle state of multi-step modals -- [NavigationProgress](https://mantine.dev/llms/x-nprogress.md): Navigation progress bar -- [Notifications system](https://mantine.dev/llms/x-notifications.md): Mantine notifications system -- [Rich text editor](https://mantine.dev/llms/x-tiptap.md): Tiptap based rich text editor -- [Spotlight](https://mantine.dev/llms/x-spotlight.md): Command center for your application - -## Other - -- [About](https://mantine.dev/llms/about.md) -- [AllReleases](https://mantine.dev/llms/changelog-all-releases.md) -- [BrowserSupport](https://mantine.dev/llms/browser-support.md) -- [Changelog700](https://mantine.dev/llms/changelog-7-0-0.md) -- [Changelog710](https://mantine.dev/llms/changelog-7-1-0.md) -- [Changelog7100](https://mantine.dev/llms/changelog-7-10-0.md) -- [Changelog7110](https://mantine.dev/llms/changelog-7-11-0.md) -- [Changelog7120](https://mantine.dev/llms/changelog-7-12-0.md) -- [Changelog7130](https://mantine.dev/llms/changelog-7-13-0.md) -- [Changelog7140](https://mantine.dev/llms/changelog-7-14-0.md) -- [Changelog7150](https://mantine.dev/llms/changelog-7-15-0.md) -- [Changelog7160](https://mantine.dev/llms/changelog-7-16-0.md) -- [Changelog7170](https://mantine.dev/llms/changelog-7-17-0.md) -- [Changelog720](https://mantine.dev/llms/changelog-7-2-0.md) -- [Changelog730](https://mantine.dev/llms/changelog-7-3-0.md) -- [Changelog740](https://mantine.dev/llms/changelog-7-4-0.md) -- [Changelog750](https://mantine.dev/llms/changelog-7-5-0.md) -- [Changelog760](https://mantine.dev/llms/changelog-7-6-0.md) -- [Changelog770](https://mantine.dev/llms/changelog-7-7-0.md) -- [Changelog780](https://mantine.dev/llms/changelog-7-8-0.md) -- [Changelog790](https://mantine.dev/llms/changelog-7-9-0.md) -- [Changelog800](https://mantine.dev/llms/changelog-8-0-0.md) -- [Changelog810](https://mantine.dev/llms/changelog-8-1-0.md) -- [Changelog820](https://mantine.dev/llms/changelog-8-2-0.md) -- [Changelog830](https://mantine.dev/llms/changelog-8-3-0.md) -- [Changelog900](https://mantine.dev/llms/changelog-9-0-0.md) -- [Changelog910](https://mantine.dev/llms/changelog-9-1-0.md) -- [Changelog920](https://mantine.dev/llms/changelog-9-2-0.md) -- [Changelog930](https://mantine.dev/llms/changelog-9-3-0.md) -- [Changelog940](https://mantine.dev/llms/changelog-9-4-0.md) -- [Changelog950](https://mantine.dev/llms/changelog-9-5-0.md) -- [Contribute](https://mantine.dev/llms/contribute.md) -- [GettingStarted](https://mantine.dev/llms/getting-started.md) -- [NotFound](https://mantine.dev/llms/404.md) -- [OxcConfig](https://mantine.dev/llms/oxc-config-mantine.md) -- [PreviousChangelogs](https://mantine.dev/llms/changelog-previous-versions.md) -- [Support](https://mantine.dev/llms/support.md) diff --git a/apps/docs/docs/advanced/environment-variables/index.mdx b/apps/docs/docs/advanced/environment-variables/index.mdx index 2c1d3e22c..f3311ed82 100644 --- a/apps/docs/docs/advanced/environment-variables/index.mdx +++ b/apps/docs/docs/advanced/environment-variables/index.mdx @@ -40,6 +40,26 @@ Using the `PUID` and `PGID` will require you to set the correct permissions on t Workshop service operators can find its server-only configuration in the [Workshop operator guide](../../workshop/operator#environment-variables). +### Workshop service + +These variables configure the separate Workshop service, not the Homarr application container. + +| Environment Variable | Description | Default | +| ------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------- | +| `WORKSHOP_PUBLIC_ORIGIN` | Public origin used in PocketBase links and email | Required in production | +| `PB_ALLOWED_ORIGINS` | Browser origins allowed to call PocketBase | `*` for the public community | +| `WORKSHOP_IMAGE` | Workshop image used by the staging Compose file | `ghcr.io/homarr-labs/workshop:v2` | +| `WORKSHOP_EXPOSE_PORT` | Host port for the combined staging service | `8090` | +| `PB_EXPOSE_PORT` | Host port for local PocketBase development | `8090` | +| `DOCS_EXPOSE_PORT` | Host port for local documentation development | `3003` | +| `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET` | Optional GitHub OAuth application credentials | - | +| `OPENROUTER_API_KEY` | Server-only upstream key that enables the Homarr Assistant provider | Provider disabled | +| `HOMARR_AI_DAILY_REQUEST_LIMIT` | Daily Assistant request units per user | `50` | +| `HOMARR_AI_GLOBAL_DAILY_REQUEST_LIMIT` | Daily Assistant request units shared by all users | `10000` | +| `HOMARR_AI_OPENROUTER_BASE_URL` | OpenRouter-compatible provider endpoint | `https://openrouter.ai/api/v1` | +| `HOMARR_AI_OPENROUTER_MODEL` | Upstream model exposed through the stable `homarr/model` alias | Selected by the Homarr team | +| `HOMARR_AI_ALLOW_INSECURE_UPSTREAM` | Allows an HTTP upstream for local provider tests; never use in production | `false` | + ## Authentication See [Single Sign-On](/docs/advanced/single-sign-on) for more informations. diff --git a/apps/docs/docs/getting-started/installation/helm.md b/apps/docs/docs/getting-started/installation/helm.md index 7507cdc18..e4c4379ce 100644 --- a/apps/docs/docs/getting-started/installation/helm.md +++ b/apps/docs/docs/getting-started/installation/helm.md @@ -2,9 +2,9 @@ homarr logo -![Version: 8.26.0](https://img.shields.io/badge/Version-8.26.0-informational?style=flat) +![Version: 8.28.1](https://img.shields.io/badge/Version-8.28.1-informational?style=flat) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat) -![AppVersion: v1.74.0](https://img.shields.io/badge/AppVersion-v1.74.0-informational?style=flat) +![AppVersion: v1.76.1](https://img.shields.io/badge/AppVersion-v1.76.1-informational?style=flat) A Helm chart to deploy homarr for Kubernetes @@ -437,7 +437,7 @@ All available values are listed on the [artifacthub](https://artifacthub.io/pack | httproute.rules[0].matches[0].path.value | string | `"/"` | Path value to match | | image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | | image.repository | string | `"ghcr.io/homarr-labs/homarr"` | Image repository | -| image.tag | string | `"v1.74.0"` | Overrides the image tag whose default is the chart appVersion | +| image.tag | string | `"v1.76.1"` | Overrides the image tag whose default is the chart appVersion | | imagePullSecrets | list | `[]` | Secrets for Docker registry | | ingress.annotations | object | `{}` | Ingress annotations | | ingress.enabled | bool | `false` | Enable ingress | diff --git a/apps/docs/docs/management/custom-widgets/agent-authoring.mdx b/apps/docs/docs/management/custom-widgets/agent-authoring.mdx index a33d1cf9b..00b7ffcb8 100644 --- a/apps/docs/docs/management/custom-widgets/agent-authoring.mdx +++ b/apps/docs/docs/management/custom-widgets/agent-authoring.mdx @@ -110,60 +110,3 @@ Agents can install existing widgets without regenerating them: 6. Test the installed definition, then use `board_addItem` with kind `customApi` and the returned definition ID. Homarr encrypts the plaintext immediately. Homarr does not return the plaintext. - -## Evaluate the copied prompt - -Homarr maintainers can run the same self-contained prompt that the workbench copies through the live generation-quality suite: - -```sh -OPENROUTER_API_KEY=... pnpm --filter @homarr/custom-widgets test:ai -``` - -The manifest suite covers nine complex and public-API prompts. Its deterministic fixture-backed cases include a fake -homelab health API, CoinMarketCap's keyless public API, Bored, Agify, and a multi-request Pokédex. Before the configured -model judges a result, the candidate must pass Homarr's real clipboard parser, canonical schema, and deterministic -checks for documented endpoints, authentication, request triggers, query bindings, response fields, and essential -runtime components. - -To exercise the real Assistant lifecycle instead of accepting a returned JSON block, run: - -```sh -OPENROUTER_API_KEY=... pnpm --filter @homarr/custom-widgets test:assistant-ai -``` - -The same suites can target the Homarr provider with a Workshop PocketBase token instead of an OpenRouter key: - -```sh -AI_PROVIDER_BASE_URL=https://homarr.dev/api/ai/v1 \ -AI_PROVIDER_API_KEY= \ -AI_PROVIDER_MODEL=homarr/model \ -pnpm --filter @homarr/custom-widgets test:assistant-ai -``` - -`AI_PROVIDER_JUDGE_MODEL` can select a separate judge when the configured endpoint offers one. The Homarr provider -offers exactly one model, so generation and review both use `homarr/model`. - -The assistant test exposes the same lazy skill, live schema, component catalog, targeted component references, -validation, preview-query, and create-from-preview tools as the product. It refuses to save a definition that was not -validated exactly or whose preview queries were not all tested. Multi-request fixtures return a different payload for -each documented path and require manual-query parameters. Use `--case=pokedex`, `--case=coinmarketcap-keyless`, -`--case=bored-activity`, or `--case=agify-name` for a focused run. - -Both suites use the configured provider models for generation and harsh review. They save tool traces, validated -manifests, raw reviews, and detailed category scores under -`packages/custom-widgets/.ai-evaluations/`. These live tests are maintainer-invoked rather than CI-required because -they consume a configured provider account and exercise a nondeterministic model. The repository's ordinary tests -cover the lifecycle enforcement, fixture routing, score calculation, and failure behavior without network access. - -Each scenario stops as soon as it passes and has a hard limit of ten generation attempts. Override the endpoint, -models, or per-scenario limit with `AI_PROVIDER_BASE_URL`, `AI_PROVIDER_API_KEY`, `AI_PROVIDER_MODEL`, -`AI_PROVIDER_JUDGE_MODEL`, and -`CUSTOM_WIDGET_AI_MAX_LOOPS`. Generated artifacts are local and ignored by Git; promote a reviewed, validated result -into the bundled-widget source deliberately. - -The reference API check uses a real PokeAPI list/detail request and a read-only Portainer container query when `PORTAINER_BASE_URL` and `PORTAINER_API_KEY` are set. Use `pnpm --filter @homarr/custom-widgets test:reference-apis -- --pokeapi-only` for the public PokeAPI check alone. To exercise start, restart, and stop against a disposable container, also set `PORTAINER_TEST_CONTAINER_ID` and the explicit safeguard `PORTAINER_ALLOW_MUTATIONS=1`; the script restores the container's original running state. - -Use `pnpm --filter @homarr/custom-widgets test:reference-apis -- --public-ai-apis-only` to verify the live Bored and -CoinMarketCap response shapes used by the assistant fixtures. The same command also verifies Agify when -`AGIFY_API_KEY` is configured; otherwise it reports the authenticated check as skipped without weakening the -deterministic Agify fixture tests. diff --git a/apps/docs/docs/management/custom-widgets/index.mdx b/apps/docs/docs/management/custom-widgets/index.mdx index 133c29c4a..b347f31f8 100644 --- a/apps/docs/docs/management/custom-widgets/index.mdx +++ b/apps/docs/docs/management/custom-widgets/index.mdx @@ -21,7 +21,8 @@ export const completeManifest = `{ :::warning Experimental feature -This feature is experimental and will probably change. If you encounter bugs, need more capabilities, or find something confusing, tell us in the [official discussion thread](https://github.com/homarr-labs/homarr/discussions/categories/custom-widgets). Your feedback directly shapes what comes next. Happy hacking! +This feature is experimental and may change. Share feedback in the +[Custom Widgets discussion](https://github.com/homarr-labs/homarr/discussions/categories/custom-widgets). ::: @@ -84,54 +85,35 @@ Mutations remain authenticated and enforce each request's view, modify, or full - [Use MCP and the skills.sh skill](./agent-authoring). - [Correct problems](./troubleshooting). -The workbench keeps one continuous layout with visual source, request, and option editors. Advanced raw JSON remains available for experts and AI paste. Invalid values stay inline and disable both preview and Save/Create until they are corrected. +The workbench provides visual source, request, and option editors, with raw JSON available for advanced use. Invalid +values remain marked and disable preview and saving until corrected. -Exports, imports, the official Workshop client, and MCP validate the same schema. PocketBase stores community -submissions without interpreting their content, and Homarr validates them before installation. Widgets saved in the v1 -format remain visible to administrators with a **Migration required** badge after upgrading. Use **Copy migration -prompt**, give the redacted prompt to an LLM, copy its single complete JSON block, then select **Paste migrated widget** -from that widget's action menu. Homarr reads the `template` value into the JSX editor automatically. The prompt keeps safe -request metadata but deliberately omits the v1 display configuration because legacy free-text and JSX can contain -hard-coded credentials. Add a credential-free description of the widget's visible layout and behavior when sending the -prompt. +Exports, imports, Workshop, and MCP validate the same schema. Homarr also validates community content before +installation. -Homarr keeps the original v1 definition and encrypted secret as a compatibility backup even after the validated v2 -replacement is created. The v2 record uses the same stable ID and takes precedence. The archived v1 copy stays hidden -while the replacement exists; deleting the v2 record surfaces the v1 entry as migration-required again. Automatic -legacy deletion is intentionally unavailable during v2 stabilization. Credentials are never included in prompts, -logs, or exports. - -For administrators adding widgets while editing a board, the Custom Widgets section includes **Import from -Workshop**. Non-administrators do not see the Custom Widget picker or Workshop actions. Selecting **Install widget** -opens a two-step modal flow: first review the Workshop entry and its complete source in the read-only editor, then -confirm API sources and credentials. After import, the new definition appears in the picker. Its tile waits for the board -to be saved before server requests run. +Legacy definitions show a **Migration required** badge. Use **Copy migration prompt**, describe the visible layout +without secrets, and import the returned v2 JSON with **Paste migrated widget**. Homarr preserves the v1 definition and +encrypted secret for rollback; credentials never appear in prompts, logs, or exports. ## Import and Workshop -The install flow always links to the corresponding public Workshop entry under the configured Workshop origin. Import confirmation shows origins, authentication modes, network scopes, methods, actions, and permissions. Every source has a suggested URL, but private and loopback sources must be confirmed or replaced for the current Homarr installation. The same screen accepts API keys, tokens, usernames, and passwords; credentials remain optional at install time and missing values stay visible on the Custom Widgets page. - -For example, installing **Tautulli Activity** asks for both the user's Tautulli URL and API key. A stable public source such as PokéAPI keeps its published URL without creating unnecessary setup work. +Administrators can select **Import from Workshop** while adding a board item. Review the complete source and requested +permissions, then confirm deployment-specific URLs and credentials. Private and loopback URLs must be confirmed or +replaced for the current Homarr installation. Workshop publishes technically valid widgets immediately; users can vote or report them, and Workshop moderators can -delete submissions. The report form expands within the Workshop detail page instead of interrupting the review with a -dialog. Community moderation is separate from Homarr administration and is not a security boundary. -Publishers should replace personal private-network hosts with a clear service placeholder before publishing. Homarr -performs definitive validation again at install time. +delete submissions. Community moderation is separate from Homarr administration and is not a security boundary. Review +the source before installation and replace personal private-network hosts before publishing. -Connected agents can search, inspect, and install Workshop widgets with `customWidget_workshopSearch`, `customWidget_workshopGet`, and `customWidget_workshopInstall`. After installation they can set a source URL and credentials with `customWidget_sourceConfigure`, or create a secure user-facing setup URL with `customWidget_configurationRequestUser`. Secret values are never returned through MCP. - -These tools are only exposed to API keys owned by Homarr administrators. Opening and completing a source-configuration -URL also requires the same authenticated administrator; the URL is short-lived, single-use, and redacted. +Connected agents can also search and install Workshop widgets. See [agent authoring](./agent-authoring) for the secure +configuration flow; secret values are never returned through MCP. ## Reliability and rollback -Custom Widget response caches and action invalidation use shared Redis state, so multiple Homarr replicas see the same -versioned cache generation. Deployments must point every replica at the same Redis service. +Multiple Homarr replicas must use the same Redis service so Custom Widget response caches invalidate consistently. -Before upgrading, back up the database and `SECRET_ENCRYPTION_KEY`; a v1 binary can still read preserved v1 tables -during application rollback. Widgets created only in v2 may be unavailable to the rolled-back binary, but do not -replace the v1 backup. +Before upgrading, back up the database and `SECRET_ENCRYPTION_KEY`. A v1 rollback can read preserved v1 definitions, +but widgets created only in v2 may be unavailable. ## Bundled examples diff --git a/apps/docs/docs/management/search-engines/index.mdx b/apps/docs/docs/management/search-engines/index.mdx index 0afe333d4..e687a16d5 100644 --- a/apps/docs/docs/management/search-engines/index.mdx +++ b/apps/docs/docs/management/search-engines/index.mdx @@ -39,7 +39,7 @@ In the configuration section you can select between two options. #### Search template -The template must be a valid URL that incldues the `%s` placeholder. +The template must be a valid URL that includes the `%s` placeholder. Homarr will replace the `%s` with the term that the user entered. ##### Examples diff --git a/apps/docs/docs/widgets/assistant/index.mdx b/apps/docs/docs/widgets/assistant/index.mdx index 0c03aecc6..4f719cc6f 100644 --- a/apps/docs/docs/widgets/assistant/index.mdx +++ b/apps/docs/docs/widgets/assistant/index.mdx @@ -11,14 +11,11 @@ import assistantWidgetImage from "../../management/img/assistant-widget.png"; -The Assistant widget brings the same conversation available from the user menu and command menu onto a -board. Messages, conversations, tool calls, approvals, files, mentions, model controls, reasoning controls, -usage details, and response actions remain synchronized with the app-wide assistant. +The Assistant widget puts the app-wide assistant on a board. It uses the same active conversation as the user-menu and +command-menu surfaces, so messages and approvals stay synchronized. -The assistant must be enabled by an administrator in **Management → Assistant**. Signed-out users and users -on an instance without an enabled model see an unavailable state instead of a broken composer. Signed-out users see -**Sign in**; a configured provider without a saved model or with **Enable Assistant** off remains unavailable until -the administrator saves a working connection, selects a model, and enables the assistant. +An administrator must first configure and enable Assistant in **Management → Assistant**. Signed-out users are prompted +to sign in, while an incomplete or disabled configuration shows an unavailable state. -The current preview capture labels the board-embedded surface: its header exposes conversation history, refresh, -automatic approvals, and new-conversation controls, while the footer exposes the model, thinking mode, and composer. - ### Adding the widget -The default widget size is ten columns by four rows and automatically fits boards with fewer columns. Controls -and labels condense as the widget becomes narrower, while the conversation remains scrollable and usable on -touch devices. When a board layout does not provide enough height for conversation controls, the widget shows -a compact **Open assistant** action instead of squeezing an unusable composer into the card. Increase its height -in that layout to keep the complete conversation inline. +The default size is ten columns by four rows and shrinks to fit narrower boards. Short layouts show an **Open +assistant** action instead of compressing the conversation controls; increase the widget height to keep the complete +conversation inline. -The widget follows whichever conversation is active in the user-menu panel, `Shift + A`, or the command menu. This -keeps every assistant entry point synchronized without storing a user's private conversation details in board settings. - -### Conversation features - -- Create, switch, rename, and delete conversations. -- Send text and supported file or image attachments by picker, drag and drop, or image paste. -- Mention permitted apps, integrations, boards, widgets, and tools with `@`. -- Use `/` shortcuts for common dashboard tasks. -- Review tool calls, approve mutations, and answer structured assistant questions inline. -- Answer pending structured questions from the dock above the composer without scrolling through the conversation. -- Enable conversation-scoped automatic approvals from the shield control to approve protected mutations, use presented form details, and choose answers categorized as affirmative without individual clicks. -- Edit user messages and copy, regenerate, branch, quote, export, or rate responses. -- Inspect syntax-highlighted Markdown, sources, generated files, tool results, streaming chain-of-thought, - cumulative conversation usage, per-turn token and context use, timing, speed, provider routing, and cost. -- Change the model and reasoning effort for the active conversation. A model choice is saved per persisted thread, - does not change the administrator's default, and is restored when that thread is selected again; a new thread - starts from the configured default. -- Refresh the current board from the conversation header. Approved mutations also refresh visible board data automatically. - -The expanded assistant and board widget use the same persisted thread runtime. A response continues in the -background when the widget leaves the viewport or the expanded panel is minimized. Each visible surface keeps an -independent draft, attachments, selection, and focus, so typing in a board widget cannot move or overwrite the -floating panel composer. - -Automatic approvals are off by default, reset when switching conversations, and never select a neutral choice. A -structured question shows **Other** only when the tool allows it (`allowOther` is not `false`); selecting **Other** -opens a manual freeform response even when automatic approvals are enabled. +Responses continue when the widget leaves the viewport. Drafts and attachments remain local to each visible Assistant +surface, and private conversation data is never stored in board settings. Normal Homarr permissions and approval rules +still apply to every action. diff --git a/apps/docs/docs/widgets/timer/index.mdx b/apps/docs/docs/widgets/timer/index.mdx index c0afc8ef5..49e208c90 100644 --- a/apps/docs/docs/widgets/timer/index.mdx +++ b/apps/docs/docs/widgets/timer/index.mdx @@ -13,35 +13,20 @@ import { timerWidget } from "."; -The Timer / Pomodoro widget runs entirely in your browser and does not require an integration. The compact widget -always keeps its start or pause button and reset button visible. A running timer uses a saved deadline, so reopening -the board or returning to a background tab restores the correct remaining time instead of restarting the countdown. +The Timer / Pomodoro widget runs in your browser and does not require an integration. A running timer uses a saved +deadline, so reopening the board or returning from a background tab restores the correct remaining time. Timer mode uses one configured duration. Pomodoro mode starts with a focus session, follows most completed focus sessions with a short break, and uses a long break after the configured number of focus sessions. Automatic break and focus starts are separate options and are disabled by default. When automatic starts are enabled, elapsed phases are reconciled from their original deadlines after the board returns to the foreground. -Advanced view shows the current sequence, configured durations, and local alert preferences. Browser notifications are -requested only when enabled. Notification and sound preferences, live progress, deadlines, and cycle position are -stored locally using the board and widget identifiers. They are separate for each browser or device, are available to -guest viewers, and are removed by clearing site data. Widget previews are ephemeral and do not write local timer state. +Advanced view shows the sequence, durations, and local alert preferences. Sounds are enabled by default, while browser +notifications are requested only after you enable them. Progress and alert preferences are stored per board and widget +in the current browser; clearing site data resets them, and widget previews do not persist timer state. -Timer sounds are enabled by default and use the same low-volume Tiks sound system as onboarding: start and pause use -rising and falling soft-theme cues, reset uses a short click, and phase completion uses the glass theme's resonant -notification ding. You can disable them in advanced view. The cues respect the device's reduced-motion preference and -supplement the visible timer state rather than replacing it. - -When automatic start is disabled, a completed phase labels the next step as ready and flashes the widget edges with the -board's secondary color. The border glow and completion chime run together as a five-beat alarm burst at -300-millisecond intervals, then stop. Reduced-motion and forced-colors modes replace the flash with a static border. -The current phase stays pinned to the compact widget's top-left corner and wraps when needed. Timer text and controls -use the dashboard theme's responsive size scale, with secondary details hidden when the widget preview is narrow or -short. - -Alerts can fire while Homarr is open. Browser and operating-system notification settings may still suppress them. -The timer's mode, durations, session count, and automatic-start behavior are permanent board settings and are edited -from the widget context menu. +Alerts can fire while Homarr is open, but browser or operating-system settings may suppress notifications. Reduced-motion +and forced-colors preferences replace the animated completion effect with a static border. diff --git a/apps/docs/docs/workshop/operator.mdx b/apps/docs/docs/workshop/operator.mdx index 777562c66..a43c53e1a 100644 --- a/apps/docs/docs/workshop/operator.mdx +++ b/apps/docs/docs/workshop/operator.mdx @@ -92,10 +92,6 @@ pnpm test:workshop-live-provider This optional check consumes one provider request. The test client needs neither the OpenRouter key nor the private upstream model ID. Do not run it in CI or with a normal user's Workshop token. -The Custom Widget AI tests can use this proxy. Set `AI_PROVIDER_BASE_URL` to the `/api/ai/v1` endpoint and -`AI_PROVIDER_API_KEY` to a temporary Workshop user token. See -[Agent authoring](../management/custom-widgets/agent-authoring#evaluate-the-copied-prompt) for the command. - ## Staging and demo deployment Use `apps/workshop/docker-compose.staging.yml` with the published `ghcr.io/homarr-labs/workshop:v2` image for a v2 @@ -133,15 +129,3 @@ sign-in, and an installation from the Homarr preview. Back up application and PocketBase data before deployment. Publish the combined image by immutable digest, test the exact digest in staging, rehearse application rollback and PocketBase restore, then promote that same digest. - -## Client architecture - -Workshop access is centralized in `@homarr/workshop/backend`. It exports the typed `WorkshopBackend`, its typed -PocketBase instance, stable TanStack Query option factories, and the `useWorkshop…` query and mutation hooks used by -Homarr. The documentation site uses the same backend rather than maintaining a second API contract. - -Listing fields derived by the `workshop_listings` view—such as submission type, score, and counts—are normalized by the -shared client. Healthy deployments keep filtering, sorting, and pagination in PocketBase. If a persistent development -volume still has an older view that rejects those fields, the client retries without them and applies the same -operations locally; it can also fall back to the base submissions collection. Production deployments should -nevertheless apply the current migration so the view exposes the complete metadata. diff --git a/apps/workshop/README.md b/apps/workshop/README.md index 527021965..f4cf84c0f 100644 --- a/apps/workshop/README.md +++ b/apps/workshop/README.md @@ -1,16 +1,10 @@ # Homarr Workshop -Workshop is the public, community-driven PocketBase service behind the Workshop pages in Homarr's Docusaurus site. It -stores Custom JSX v2 widgets and Custom CSS submissions. Installation-time validation inside Homarr remains -authoritative: public content must be reviewed before it is installed. +Workshop is the PocketBase service behind the community pages in Homarr's documentation site. It stores Custom JSX v2 +widgets and Custom CSS submissions. Homarr validates community content again before installation. -The runtime base is PocketBase 0.39.9 pinned by its multi-platform OCI digest in `apps/workshop/Dockerfile`. Update the -version and digest together, then run the Workshop integration and production-image smoke suites. - -The internal PocketBase field `users.isAdmin` means **Workshop moderator**. It does not grant Homarr administrator -access. Signed-in moderators can open `/workshop/admin` from the visible **Moderation** button, review private report -details, dismiss reports, and remove submissions or comments. Public submission cards show only the open report count; -the submission author can read the report category and explanation without receiving the reporter identity. +The PocketBase version and multi-platform image digest are pinned in `apps/workshop/Dockerfile`; update and validate +them together. ## Run locally @@ -22,39 +16,28 @@ pnpm install --frozen-lockfile docker compose --env-file apps/workshop/.env -f apps/workshop/docker-compose.yml up --build workshop ``` -This starts persistent PocketBase at `http://127.0.0.1:8090`. Start Docusaurus in another terminal: +Start the documentation site in another terminal: ```sh WORKSHOP_API_URL=http://127.0.0.1:8090 pnpm dev:docs ``` -Open: - -- PocketBase administration: `http://127.0.0.1:8090/_/` -- Workshop: `http://127.0.0.1:3003/workshop` - -Create the first PocketBase superuser in the administration UI, or use: +Open PocketBase administration at `http://127.0.0.1:8090/_/` and Workshop at +`http://127.0.0.1:3003/workshop`. Create the first PocketBase superuser in the administration UI or run: ```sh docker compose -f apps/workshop/docker-compose.yml exec workshop \ pocketbase superuser create you@example.com 'replace-with-a-strong-password' --dir=/pb_data ``` -Stopping the Compose process preserves `homarr-workshop_pb_data`. To inspect or stop the service separately: +Useful service commands: ```sh docker compose -f apps/workshop/docker-compose.yml logs -f workshop docker compose -f apps/workshop/docker-compose.yml stop workshop ``` -### Pre-release migration reset - -The v2 branch consolidates the unreleased Workshop migrations into one initial migration. A PocketBase volume that ran -an earlier v2 Workshop migration chain is unsupported. Back up anything you need, then use the intentional local reset -command near the end of this document and start the stack again. Startup never deletes a volume automatically. This -exception applies only to disposable pre-release volumes and must not be used for production data. - -## Connect the Homarr application +## Connect Homarr Use the same URL contract in the repository-root `.env`, then restart Homarr: @@ -66,54 +49,26 @@ WORKSHOP_PUBLIC_ORIGIN=http://127.0.0.1:3003 PB_ALLOWED_ORIGINS=* ``` -```sh -pnpm dev -``` +`WORKSHOP_API_URL` controls API calls, `WORKSHOP_WEB_URL` controls links from Homarr, and +`HOMARR_WEBSITE_URL` is the documentation-site base. All three must be absolute HTTP(S) URLs. -`WORKSHOP_API_URL` controls API calls. `WORKSHOP_WEB_URL` controls links from Homarr. `HOMARR_WEBSITE_URL` is the -documentation/site base. All three must be absolute HTTP(S) URLs. The old Docusaurus-only `WORKSHOP_URL` variable -remains a deprecated alias for one release. The production image writes these values into the browser runtime -configuration at container startup, so changing them requires a restart but not an image rebuild. +## OAuth and moderators -## Optional GitHub OAuth - -Create a GitHub OAuth application with this callback: +For optional GitHub OAuth, set both `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET`. The callback is: ```text https:///api/oauth2-redirect ``` -Set both credentials in `.env`: +After a user signs in, a PocketBase superuser can promote them by setting `users.isAdmin` to `true`. This grants +Workshop moderation only; it does not grant Homarr administrator access. The user must sign in again after the change. -```dotenv -GITHUB_CLIENT_ID=... -GITHUB_CLIENT_SECRET=... -``` +The public community uses `PB_ALLOWED_ORIGINS=*` because self-hosted Homarr instances can run on any origin. Private +deployments can use an explicit comma-separated allowlist. -OAuth settings synchronize on every PocketBase startup. Restart after rotation. A production deployment must never -supply only one credential. `PB_ALLOWED_ORIGINS=*` is appropriate for the central community because arbitrary -self-hosted Homarr origins must open its OAuth popup; a restricted list must include every allowed browser origin. -Workshop stores only the OAuth provider username in `users.name`; users cannot rename it. PocketBase maps -**OAuth2 username** to `name` and leaves the OAuth2 id, full name, and avatar mappings empty. GitHub profiles -and avatars are derived from `https://github.com/` and `https://github.com/.png`, so no duplicate -profile metadata or avatar file is stored. +## Validate changes -## Promote a Workshop moderator - -Sign in once through GitHub so the user record exists. In the PocketBase administration UI, open the `users` collection -and set `isAdmin` to `true`. The user must sign in again. Set it back to `false` to remove moderator access. - -Regular API rules cannot set this field. Never describe a Workshop moderator as a Homarr administrator: they are -separate roles in separate services. - -## Validation and tests - -The official browser and shared client validate content with the canonical TypeScript schema and send the matching -schema identifier. PocketBase stores submission content without parsing, normalizing, or validating it; it only owns -revision fields and rejects stale compare-and-swap updates. Homarr validates downloaded content again before -installation, so direct API submissions that bypass the official client can be rejected there. - -Run the disposable integration suite: +Run the focused Workshop checks: ```sh pnpm test:workshop @@ -121,125 +76,25 @@ pnpm --filter @homarr/workshop typecheck pnpm --filter @homarr/docs typecheck ``` -The integration suite uses a separate Compose project and deletes only its disposable volume. +The integration suite uses a disposable Compose project. `pnpm test:workshop-image` additionally builds and smoke-tests +the combined production image. -To smoke-test a deployed Workshop against its real configured upstream, use a dedicated low-quota test user: +## Data safety -```sh -HOMARR_AI_LIVE_SMOKE=1 \ -WORKSHOP_LIVE_TEST_URL=https://workshop.example.com \ -WORKSHOP_LIVE_TEST_TOKEN= \ -pnpm test:workshop-live-provider -``` +PocketBase data lives in `/pb_data`. Normal start, stop, and down operations retain the named volume. Back up the +database before migrations or image promotion, and test restores in a separate empty volume. -This opt-in check consumes one real request. It verifies the stable model contract, an authenticated completion, quota -headers, and server-side user accounting without requiring the OpenRouter key or upstream model on the test client. - -## Backup and restore - -PocketBase data lives in `/pb_data`. Stop writes and copy it into a new, empty host directory for each -filesystem-level backup: - -```sh -docker compose -f apps/workshop/docker-compose.yml stop workshop -docker compose -f apps/workshop/docker-compose.yml cp workshop:/pb_data/. ./workshop-backup -docker compose -f apps/workshop/docker-compose.yml start workshop -``` - -Never copy a backup over a non-empty PocketBase volume: files created after the backup could survive and make the -restore inconsistent. For a development restore, first verify that the selected backup contains the database, then -empty the stopped volume before copying it: - -```sh -test -f ./workshop-backup/data.db -docker compose -f apps/workshop/docker-compose.yml stop workshop -docker compose -f apps/workshop/docker-compose.yml run --rm --no-deps --entrypoint sh workshop \ - -c 'find /pb_data -mindepth 1 -maxdepth 1 -exec rm -rf {} +' -docker compose -f apps/workshop/docker-compose.yml cp ./workshop-backup/. workshop:/pb_data -docker compose -f apps/workshop/docker-compose.yml start workshop -curl --fail http://127.0.0.1:8090/api/health -curl --fail 'http://127.0.0.1:8090/api/collections/workshop_listings/records?perPage=1' -``` - -The cleanup command irreversibly empties the selected Compose volume, so confirm the backup path and preserve the -current volume separately before running it. After the HTTP checks, verify sign-in, reports, and a test installation. -Production backups must be versioned, access-controlled, restored into a clean staging volume, and validated before a -release. - -## Production image and operations - -The production target serves the built documentation from `/pb_public` and PocketBase from the same image. Required -production configuration: - -```dotenv -HOMARR_WEBSITE_URL=https://homarr.dev -WORKSHOP_API_URL=https://homarr.dev -WORKSHOP_WEB_URL=https://homarr.dev/workshop -WORKSHOP_PUBLIC_ORIGIN=https://homarr.dev -PB_ALLOWED_ORIGINS=* -``` - -### Deploy a v2 staging or demo instance - -The staging Compose file runs the published `ghcr.io/homarr-labs/workshop:v2` image, persists `/pb_data`, binds only to -the host loopback interface, and expects TLS to terminate at a reverse proxy. It does not need a repository checkout to -run; copy `docker-compose.staging.yml` and `.env.staging.example` to the deployment host, then: - -```sh -cp .env.staging.example .env.staging -docker compose --env-file .env.staging -f docker-compose.staging.yml pull -docker compose --env-file .env.staging -f docker-compose.staging.yml up --detach -docker compose --env-file .env.staging -f docker-compose.staging.yml ps -curl --fail http://127.0.0.1:8090/api/health -``` - -The checked-in example is ready for `https://v2.preview.homarr.dev`: - -```dotenv -HOMARR_WEBSITE_URL=https://v2.preview.homarr.dev -WORKSHOP_API_URL=https://v2.preview.homarr.dev -WORKSHOP_WEB_URL=https://v2.preview.homarr.dev/workshop -WORKSHOP_PUBLIC_ORIGIN=https://v2.preview.homarr.dev -PB_ALLOWED_ORIGINS=* -``` - -Proxy the entire `v2.preview.homarr.dev` hostname to `http://127.0.0.1:8090`, including `/api`, `/_/`, and -`/workshop-runtime-config.js`; do not proxy only `/workshop`. The combined image owns both the Docusaurus pages and -PocketBase routes. If the hostname already serves the Homarr application, use a dedicated Workshop hostname instead -and set all four public URL variables to that hostname (with `/workshop` only on `WORKSHOP_WEB_URL`). - -The `v2` image tag is intentionally convenient and mutable for previews. Run `pull` followed by `up --detach` to test a -new v2 image while retaining the named PocketBase volume. Use the immutable `sha-` image tag when promoting a -tested build. The public central Workshop needs `PB_ALLOWED_ORIGINS=*` because Homarr instances on arbitrary origins -call the API and open the OAuth flow; a private demo can instead use a comma-separated allowlist of its browser origins. - -After startup, open `https://v2.preview.homarr.dev/_/` to create the first PocketBase superuser. If GitHub OAuth is -enabled, configure its callback as `https://v2.preview.homarr.dev/api/oauth2-redirect`, set both GitHub credentials, and -restart the service. Verify `/workshop`, `/api/health`, listing requests, sign-in, and one installation from the Homarr -preview before sharing the demo. - -Build and smoke-test the combined image locally: - -```sh -docker compose -f apps/workshop/docker-compose.yml --profile docs up --build --detach docs -curl --fail http://127.0.0.1:3003/api/health -curl --fail http://127.0.0.1:3003/ -curl --fail http://127.0.0.1:3003/workshop -docker compose -f apps/workshop/docker-compose.yml --profile docs stop docs -``` - -`pnpm test:workshop-image` builds the production target, starts it with the preview URL contract, and proves that the -browser runtime configuration, Workshop page, health endpoint, migrations, public listing endpoint, and cross-origin -browser access all work. - -Normal `up`, `start`, `stop`, and `down` operations retain the named volume. The following command is an intentional, -irreversible local reset: +The v2 branch consolidates the unreleased Workshop migrations. Volumes that ran an earlier v2 migration chain are +unsupported and must be backed up and recreated. The following command permanently removes the local Workshop volume: ```sh docker compose -f apps/workshop/docker-compose.yml down --volumes ``` -Never run the reset command against production. Release by immutable image digest, back up application and PocketBase -data first, rehearse restore and rollback in staging, and promote the exact tested digest. The Algolia recrawl workflow -remains manual until the external Homarr website host can dispatch it after promotion; publishing the image to GHCR does -not make that image live. +Never run that reset against production. + +## Production + +The production image serves the documentation site and PocketBase from one origin. See the +[Workshop operator guide](../docs/docs/workshop/operator.mdx) for environment variables, proxying, staging, backups, +and promotion. Publish by immutable digest, validate that exact digest in staging, then promote it. diff --git a/package.json b/package.json index 477724057..edbd669c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homarr", - "version": "1.74.0", + "version": "2.0.0", "private": true, "scripts": { "build": "cross-env CI=true turbo build",