chore(release): automatic release v1.46.0
This commit is contained in:
43
.github/actions/extract-build-artifact/action.yaml
vendored
Normal file
43
.github/actions/extract-build-artifact/action.yaml
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
name: Extract Build Artifact
|
||||||
|
description: Extracts artifacts from an existing Docker image to be used for from source installation
|
||||||
|
inputs:
|
||||||
|
digest:
|
||||||
|
description: Digest of Docker image to use
|
||||||
|
required: true
|
||||||
|
architecture:
|
||||||
|
description: Name of architecture, will be used to create directories (e.g. amd64, arm64)
|
||||||
|
required: true
|
||||||
|
release-tag:
|
||||||
|
description: Tag of the release to which the artifact will be attached
|
||||||
|
required: true
|
||||||
|
repository:
|
||||||
|
description: Repository to which the release belongs, e.g. owner/repo
|
||||||
|
required: true
|
||||||
|
token:
|
||||||
|
description: GitHub token with permissions to upload release assets
|
||||||
|
required: true
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Start docker container for ${{ inputs.architecture }}
|
||||||
|
run: |
|
||||||
|
docker run --name homarr \
|
||||||
|
-e "SECRET_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000" \
|
||||||
|
--detach --rm ${{ inputs.digest }}
|
||||||
|
shell: bash
|
||||||
|
- name: Extract build from ${{ inputs.architecture }} container
|
||||||
|
run: |
|
||||||
|
docker exec homarr cp /etc/nginx/templates/nginx.conf /app && \
|
||||||
|
docker exec homarr tar -czf extraction.tar.gz -C /app . && \
|
||||||
|
mkdir -p ${{ runner.temp }}/extraction/${{ inputs.architecture }} && \
|
||||||
|
docker cp homarr:/app/extraction.tar.gz ${{ runner.temp }}/extraction/${{ inputs.architecture }}/build-${{ inputs.architecture }}.tar.gz
|
||||||
|
shell: bash
|
||||||
|
- name: Stop ${{ inputs.architecture }} container
|
||||||
|
if: always()
|
||||||
|
run: docker container remove --force --volumes homarr
|
||||||
|
shell: bash
|
||||||
|
- name: Add build archive to release
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ inputs.token }}
|
||||||
|
run: gh release upload --repo ${{ inputs.repository }} ${{ inputs.release-tag }} ${{ runner.temp }}/extraction/${{ inputs.architecture }}/build-${{ inputs.architecture }}.tar.gz --clobber
|
||||||
|
shell: bash
|
||||||
40
.github/workflows/deployment-docker-image.yml
vendored
40
.github/workflows/deployment-docker-image.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
version: ${{ steps.read-semver.outputs.version || steps.version-fallback.outputs.version }}
|
version: ${{ steps.read-semver.outputs.version || steps.version-fallback.outputs.version }}
|
||||||
git_ref: ${{ steps.read-git-ref.outputs.ref || github.ref }}
|
git_ref: ${{ steps.read-git-ref.outputs.ref || github.ref }}
|
||||||
|
skipped: ${{ env.SKIP_RELEASE }}
|
||||||
steps:
|
steps:
|
||||||
- run: echo "Skipping release for workflow_dispatch event"
|
- run: echo "Skipping release for workflow_dispatch event"
|
||||||
if: env.SKIP_RELEASE == 'true'
|
if: env.SKIP_RELEASE == 'true'
|
||||||
@@ -146,7 +146,6 @@ jobs:
|
|||||||
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
||||||
env:
|
env:
|
||||||
SKIP_ENV_VALIDATION: true
|
SKIP_ENV_VALIDATION: true
|
||||||
|
|
||||||
build-arm64:
|
build-arm64:
|
||||||
name: Build docker image for arm64
|
name: Build docker image for arm64
|
||||||
needs: release
|
needs: release
|
||||||
@@ -185,10 +184,38 @@ jobs:
|
|||||||
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
||||||
env:
|
env:
|
||||||
SKIP_ENV_VALIDATION: true
|
SKIP_ENV_VALIDATION: true
|
||||||
|
extract-asset-amd64:
|
||||||
|
name: Extract amd64 asset from docker image
|
||||||
|
needs: [release, build-amd64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Extract amd64
|
||||||
|
if: needs.release.outputs.skipped == 'false'
|
||||||
|
uses: homarr-labs/homarr/.github/actions/extract-build-artifact@dev
|
||||||
|
with:
|
||||||
|
digest: "${{ env.GHCR_REPO }}@${{ needs.build-amd64.outputs.digest }}"
|
||||||
|
architecture: amd64
|
||||||
|
release-tag: ${{ needs.release.outputs.version }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
repository: ${{ github.repository }}
|
||||||
|
|
||||||
|
extract-asset-arm64:
|
||||||
|
name: Extract arm64 asset from docker image
|
||||||
|
needs: [release, build-arm64]
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
steps:
|
||||||
|
- name: Extract arm64
|
||||||
|
if: needs.release.outputs.skipped == 'false'
|
||||||
|
uses: homarr-labs/homarr/.github/actions/extract-build-artifact@dev
|
||||||
|
with:
|
||||||
|
digest: "${{ env.GHCR_REPO }}@${{ needs.build-arm64.outputs.digest }}"
|
||||||
|
architecture: arm64
|
||||||
|
release-tag: ${{ needs.release.outputs.version }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
repository: ${{ github.repository }}
|
||||||
publish:
|
publish:
|
||||||
name: Complete deployment and notify
|
name: Complete deployment and notify
|
||||||
needs: [release, build-amd64, build-arm64]
|
needs: [release, build-amd64, build-arm64, extract-asset-amd64, extract-asset-arm64]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
NEXT_VERSION: ${{ needs.release.outputs.version }}
|
NEXT_VERSION: ${{ needs.release.outputs.version }}
|
||||||
@@ -222,6 +249,13 @@ jobs:
|
|||||||
${{ env.GHCR_REPO }}@${{ needs.build-amd64.outputs.digest }} \
|
${{ env.GHCR_REPO }}@${{ needs.build-amd64.outputs.digest }} \
|
||||||
${{ env.GHCR_REPO }}@${{ needs.build-arm64.outputs.digest }}
|
${{ env.GHCR_REPO }}@${{ needs.build-arm64.outputs.digest }}
|
||||||
|
|
||||||
|
- name: Publish release
|
||||||
|
if: needs.release.outputs.skipped == 'false'
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
gh release edit --repo ${{ github.repository }} ${{ needs.release.outputs.version }} --draft=false
|
||||||
|
|
||||||
- name: Discord notification
|
- name: Discord notification
|
||||||
env:
|
env:
|
||||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
{
|
{
|
||||||
"successComment": false,
|
"successComment": false,
|
||||||
"failComment": false,
|
"failComment": false,
|
||||||
|
"draftRelease": true,
|
||||||
"releaseBodyTemplate": "<%= _.truncate(nextRelease.notes, { 'length': 124000, 'omission': '' }) %>"
|
"releaseBodyTemplate": "<%= _.truncate(nextRelease.notes, { 'length': 124000, 'omission': '' }) %>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
"@mantine/tiptap": "^8.3.9",
|
"@mantine/tiptap": "^8.3.9",
|
||||||
"@million/lint": "1.0.14",
|
"@million/lint": "1.0.14",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"@tanstack/react-query": "^5.90.11",
|
"@tanstack/react-query": "^5.90.12",
|
||||||
"@tanstack/react-query-devtools": "^5.91.1",
|
"@tanstack/react-query-devtools": "^5.91.1",
|
||||||
"@tanstack/react-query-next-experimental": "^5.91.0",
|
"@tanstack/react-query-next-experimental": "^5.91.0",
|
||||||
"@trpc/client": "^11.7.2",
|
"@trpc/client": "^11.7.2",
|
||||||
@@ -78,11 +78,11 @@
|
|||||||
"isomorphic-dompurify": "^2.33.0",
|
"isomorphic-dompurify": "^2.33.0",
|
||||||
"jotai": "^2.15.2",
|
"jotai": "^2.15.2",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"postcss-preset-mantine": "^1.18.0",
|
"postcss-preset-mantine": "^1.18.0",
|
||||||
"prismjs": "^1.30.0",
|
"prismjs": "^1.30.0",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"react-error-boundary": "^6.0.0",
|
"react-error-boundary": "^6.0.0",
|
||||||
"react-simple-code-editor": "^0.14.1",
|
"react-simple-code-editor": "^0.14.1",
|
||||||
"sass": "^1.94.2",
|
"sass": "^1.94.2",
|
||||||
|
|||||||
@@ -64,16 +64,23 @@ export const RegistrationForm = ({ invite }: RegistrationFormProps) => {
|
|||||||
<Stack gap="xl">
|
<Stack gap="xl">
|
||||||
<form onSubmit={form.onSubmit(handleSubmit)}>
|
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<TextInput label={t("field.username.label")} autoComplete="off" {...form.getInputProps("username")} />
|
<TextInput
|
||||||
|
label={t("field.username.label")}
|
||||||
|
id="username"
|
||||||
|
autoComplete="username"
|
||||||
|
{...form.getInputProps("username")}
|
||||||
|
/>
|
||||||
<CustomPasswordInput
|
<CustomPasswordInput
|
||||||
withPasswordRequirements
|
withPasswordRequirements
|
||||||
label={t("field.password.label")}
|
label={t("field.password.label")}
|
||||||
|
id="password"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
{...form.getInputProps("password")}
|
{...form.getInputProps("password")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label={t("field.passwordConfirm.label")}
|
label={t("field.passwordConfirm.label")}
|
||||||
|
id="password-confirm"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
{...form.getInputProps("confirmPassword")}
|
{...form.getInputProps("confirmPassword")}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -116,8 +116,18 @@ export const LoginForm = ({ providers, oidcClientName, isOidcAutoLoginEnabled, c
|
|||||||
<>
|
<>
|
||||||
<form onSubmit={form.onSubmit((credentials) => void signInAsync(credentials.provider, credentials))}>
|
<form onSubmit={form.onSubmit((credentials) => void signInAsync(credentials.provider, credentials))}>
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<TextInput label={t("field.username.label")} {...form.getInputProps("name")} />
|
<TextInput
|
||||||
<PasswordInput label={t("field.password.label")} {...form.getInputProps("password")} />
|
label={t("field.username.label")}
|
||||||
|
id="username"
|
||||||
|
autoComplete="username"
|
||||||
|
{...form.getInputProps("name")}
|
||||||
|
/>
|
||||||
|
<PasswordInput
|
||||||
|
label={t("field.password.label")}
|
||||||
|
id="password"
|
||||||
|
autoComplete="current-password"
|
||||||
|
{...form.getInputProps("password")}
|
||||||
|
/>
|
||||||
|
|
||||||
{providers.includes("credentials") && (
|
{providers.includes("credentials") && (
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"dotenv-cli": "^11.0.0",
|
"dotenv-cli": "^11.0.0",
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.7.4",
|
||||||
"tsx": "4.20.4",
|
"tsx": "4.20.4",
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.7.4",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
"@semantic-release/npm": "^13.1.2",
|
"@semantic-release/npm": "^13.1.2",
|
||||||
"@semantic-release/release-notes-generator": "^14.1.0",
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
||||||
"@testcontainers/redis": "^11.9.0",
|
"@testcontainers/redis": "^11.9.0",
|
||||||
"@turbo/gen": "^2.6.1",
|
"@turbo/gen": "^2.6.3",
|
||||||
"@vitejs/plugin-react": "^5.1.1",
|
"@vitejs/plugin-react": "^5.1.1",
|
||||||
"@vitest/coverage-v8": "^4.0.15",
|
"@vitest/coverage-v8": "^4.0.15",
|
||||||
"@vitest/ui": "^4.0.15",
|
"@vitest/ui": "^4.0.15",
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
"prettier": "^3.7.4",
|
"prettier": "^3.7.4",
|
||||||
"semantic-release": "^25.0.2",
|
"semantic-release": "^25.0.2",
|
||||||
"testcontainers": "^11.9.0",
|
"testcontainers": "^11.9.0",
|
||||||
"turbo": "^2.6.1",
|
"turbo": "^2.6.3",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
"vitest": "^4.0.15"
|
"vitest": "^4.0.15"
|
||||||
@@ -82,14 +82,14 @@
|
|||||||
"axios@>=1.0.0 <1.8.2": ">=1.13.2",
|
"axios@>=1.0.0 <1.8.2": ">=1.13.2",
|
||||||
"brace-expansion@>=2.0.0 <=2.0.1": ">=4.0.1",
|
"brace-expansion@>=2.0.0 <=2.0.1": ">=4.0.1",
|
||||||
"brace-expansion@>=1.0.0 <=1.1.11": ">=4.0.1",
|
"brace-expansion@>=1.0.0 <=1.1.11": ">=4.0.1",
|
||||||
"esbuild@<=0.24.2": ">=0.27.0",
|
"esbuild@<=0.24.2": ">=0.27.1",
|
||||||
"form-data@>=4.0.0 <4.0.4": ">=4.0.5",
|
"form-data@>=4.0.0 <4.0.4": ">=4.0.5",
|
||||||
"hono@<4.6.5": ">=4.10.7",
|
"hono@<4.6.5": ">=4.10.7",
|
||||||
"linkifyjs@<4.3.2": ">=4.3.2",
|
"linkifyjs@<4.3.2": ">=4.3.2",
|
||||||
"nanoid@>=4.0.0 <5.0.9": ">=5.1.6",
|
"nanoid@>=4.0.0 <5.0.9": ">=5.1.6",
|
||||||
"prismjs@<1.30.0": ">=1.30.0",
|
"prismjs@<1.30.0": ">=1.30.0",
|
||||||
"proxmox-api>undici": "7.16.0",
|
"proxmox-api>undici": "7.16.0",
|
||||||
"react-is": "^19.2.0",
|
"react-is": "^19.2.1",
|
||||||
"rollup@>=4.0.0 <4.22.4": ">=4.53.3",
|
"rollup@>=4.0.0 <4.22.4": ">=4.53.3",
|
||||||
"sha.js@<=2.4.11": ">=2.4.12",
|
"sha.js@<=2.4.11": ">=2.4.12",
|
||||||
"tar-fs@>=3.0.0 <3.0.9": ">=3.1.1",
|
"tar-fs@>=3.0.0 <3.0.9": ">=3.1.1",
|
||||||
|
|||||||
@@ -43,15 +43,15 @@
|
|||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"@kubernetes/client-node": "^1.4.0",
|
"@kubernetes/client-node": "^1.4.0",
|
||||||
"@tanstack/react-query": "^5.90.11",
|
"@tanstack/react-query": "^5.90.12",
|
||||||
"@trpc/client": "^11.7.2",
|
"@trpc/client": "^11.7.2",
|
||||||
"@trpc/react-query": "^11.7.2",
|
"@trpc/react-query": "^11.7.2",
|
||||||
"@trpc/server": "^11.7.2",
|
"@trpc/server": "^11.7.2",
|
||||||
"@trpc/tanstack-react-query": "^11.7.2",
|
"@trpc/tanstack-react-query": "^11.7.2",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"superjson": "2.2.6",
|
"superjson": "2.2.6",
|
||||||
"trpc-to-openapi": "^3.1.0",
|
"trpc-to-openapi": "^3.1.0",
|
||||||
"zod": "^4.1.13"
|
"zod": "^4.1.13"
|
||||||
|
|||||||
@@ -34,11 +34,11 @@
|
|||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
"cookies": "^0.9.1",
|
"cookies": "^0.9.1",
|
||||||
"ldapts": "8.0.9",
|
"ldapts": "8.0.14",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"next-auth": "5.0.0-beta.30",
|
"next-auth": "5.0.0-beta.30",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"zod": "^4.1.13"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/api": "workspace:^0.1.0",
|
"@homarr/api": "workspace:^0.1.0",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0"
|
"react-dom": "19.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,10 +32,10 @@
|
|||||||
"@paralleldrive/cuid2": "^3.1.0",
|
"@paralleldrive/cuid2": "^3.1.0",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"dns-caching": "^0.2.7",
|
"dns-caching": "^0.2.7",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"octokit": "^5.0.5",
|
"octokit": "^5.0.5",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"undici": "7.16.0",
|
"undici": "7.16.0",
|
||||||
"zod": "^4.1.13",
|
"zod": "^4.1.13",
|
||||||
"zod-validation-error": "^5.0.0"
|
"zod-validation-error": "^5.0.0"
|
||||||
|
|||||||
@@ -29,12 +29,12 @@
|
|||||||
"@homarr/core": "workspace:^0.1.0",
|
"@homarr/core": "workspace:^0.1.0",
|
||||||
"@homarr/cron-jobs": "workspace:^0.1.0",
|
"@homarr/cron-jobs": "workspace:^0.1.0",
|
||||||
"@homarr/log": "workspace:^0.1.0",
|
"@homarr/log": "workspace:^0.1.0",
|
||||||
"@tanstack/react-query": "^5.90.11",
|
"@tanstack/react-query": "^5.90.12",
|
||||||
"@trpc/client": "^11.7.2",
|
"@trpc/client": "^11.7.2",
|
||||||
"@trpc/server": "^11.7.2",
|
"@trpc/server": "^11.7.2",
|
||||||
"@trpc/tanstack-react-query": "^11.7.2",
|
"@trpc/tanstack-react-query": "^11.7.2",
|
||||||
"node-cron": "^4.2.1",
|
"node-cron": "^4.2.1",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"zod": "^4.1.13"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -53,10 +53,10 @@
|
|||||||
"@paralleldrive/cuid2": "^3.1.0",
|
"@paralleldrive/cuid2": "^3.1.0",
|
||||||
"@testcontainers/mysql": "^11.9.0",
|
"@testcontainers/mysql": "^11.9.0",
|
||||||
"@testcontainers/postgresql": "^11.9.0",
|
"@testcontainers/postgresql": "^11.9.0",
|
||||||
"better-sqlite3": "^12.4.1",
|
"better-sqlite3": "^12.5.0",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"drizzle-kit": "^0.31.7",
|
"drizzle-kit": "^0.31.8",
|
||||||
"drizzle-orm": "^0.44.7",
|
"drizzle-orm": "^0.45.0",
|
||||||
"drizzle-zod": "^0.8.3",
|
"drizzle-zod": "^0.8.3",
|
||||||
"mysql2": "3.15.3",
|
"mysql2": "3.15.3",
|
||||||
"pg": "^8.16.3",
|
"pg": "^8.16.3",
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
"@types/better-sqlite3": "7.6.13",
|
"@types/better-sqlite3": "7.6.13",
|
||||||
"@types/pg": "^8.15.6",
|
"@types/pg": "^8.15.6",
|
||||||
"dotenv-cli": "^11.0.0",
|
"dotenv-cli": "^11.0.0",
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.7.4",
|
||||||
"tsx": "4.20.4",
|
"tsx": "4.20.4",
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
"@homarr/ui": "workspace:^0.1.0",
|
"@homarr/ui": "workspace:^0.1.0",
|
||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"@mantine/core": "^8.3.9",
|
"@mantine/core": "^8.3.9",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"zod": "^4.1.13"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export class TransmissionIntegration extends Integration implements IDownloadCli
|
|||||||
name: torrent.name,
|
name: torrent.name,
|
||||||
size: torrent.totalSize,
|
size: torrent.totalSize,
|
||||||
sent: torrent.uploadedEver,
|
sent: torrent.uploadedEver,
|
||||||
|
received: torrent.downloadedEver,
|
||||||
downSpeed: torrent.percentDone !== 1 ? torrent.rateDownload : undefined,
|
downSpeed: torrent.percentDone !== 1 ? torrent.rateDownload : undefined,
|
||||||
upSpeed: torrent.rateUpload,
|
upSpeed: torrent.rateUpload,
|
||||||
time:
|
time:
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ export const downloadClientItemSchema = z.object({
|
|||||||
size: z.number(),
|
size: z.number(),
|
||||||
/** Total uploaded in Bytes, only required for Torrent items */
|
/** Total uploaded in Bytes, only required for Torrent items */
|
||||||
sent: z.number().optional(),
|
sent: z.number().optional(),
|
||||||
|
/** Total downloaded in Bytes, only required for Torrent items */
|
||||||
|
received: z.number().optional(),
|
||||||
/** Download speed in Bytes/s, only required if not complete
|
/** Download speed in Bytes/s, only required if not complete
|
||||||
* (Says 0 only if it should be downloading but isn't) */
|
* (Says 0 only if it should be downloading but isn't) */
|
||||||
downSpeed: z.number().optional(),
|
downSpeed: z.number().optional(),
|
||||||
|
|||||||
@@ -169,17 +169,15 @@ export class PlexIntegration extends Integration implements IMediaServerIntegrat
|
|||||||
protected async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> {
|
protected async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> {
|
||||||
const token = super.getSecretValue("apiKey");
|
const token = super.getSecretValue("apiKey");
|
||||||
|
|
||||||
const response = await input.fetchAsync(this.url("/"), {
|
const response = await input.fetchAsync(super.url("/prefs"), {
|
||||||
headers: {
|
headers: {
|
||||||
"X-Plex-Token": token,
|
"X-Plex-Token": token,
|
||||||
|
Accept: "application/json",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) return TestConnectionError.StatusResult(response);
|
if (!response.ok) return TestConnectionError.StatusResult(response);
|
||||||
|
|
||||||
const result = await response.text();
|
|
||||||
|
|
||||||
await PlexIntegration.parseXmlAsync<PlexResponse>(result);
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/core": "workspace:^0.1.0",
|
"@homarr/core": "workspace:^0.1.0",
|
||||||
"superjson": "2.2.6",
|
"superjson": "2.2.6",
|
||||||
"winston": "3.18.3",
|
"winston": "3.19.0",
|
||||||
"zod": "^4.1.13"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -36,9 +36,9 @@
|
|||||||
"@mantine/core": "^8.3.9",
|
"@mantine/core": "^8.3.9",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"zod": "^4.1.13"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"@homarr/ui": "workspace:^0.1.0",
|
"@homarr/ui": "workspace:^0.1.0",
|
||||||
"@mantine/core": "^8.3.9",
|
"@mantine/core": "^8.3.9",
|
||||||
"@mantine/hooks": "^8.3.9",
|
"@mantine/hooks": "^8.3.9",
|
||||||
"react": "19.2.0"
|
"react": "19.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -40,9 +40,9 @@
|
|||||||
"@mantine/core": "^8.3.9",
|
"@mantine/core": "^8.3.9",
|
||||||
"@mantine/hooks": "^8.3.9",
|
"@mantine/hooks": "^8.3.9",
|
||||||
"adm-zip": "0.5.16",
|
"adm-zip": "0.5.16",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"superjson": "2.2.6",
|
"superjson": "2.2.6",
|
||||||
"zod": "^4.1.13",
|
"zod": "^4.1.13",
|
||||||
"zod-form-data": "^3.0.1"
|
"zod-form-data": "^3.0.1"
|
||||||
|
|||||||
@@ -27,9 +27,9 @@
|
|||||||
"@homarr/db": "workspace:^0.1.0",
|
"@homarr/db": "workspace:^0.1.0",
|
||||||
"@homarr/server-settings": "workspace:^0.1.0",
|
"@homarr/server-settings": "workspace:^0.1.0",
|
||||||
"@mantine/dates": "^8.3.9",
|
"@mantine/dates": "^8.3.9",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0"
|
"react-dom": "19.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -38,9 +38,9 @@
|
|||||||
"@mantine/spotlight": "^8.3.9",
|
"@mantine/spotlight": "^8.3.9",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"jotai": "^2.15.2",
|
"jotai": "^2.15.2",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"use-deep-compare-effect": "^1.8.1"
|
"use-deep-compare-effect": "^1.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -32,10 +32,10 @@
|
|||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"deepmerge": "4.3.1",
|
"deepmerge": "4.3.1",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"next-intl": "4.5.8",
|
"next-intl": "4.5.8",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0"
|
"react-dom": "19.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -1939,7 +1939,23 @@
|
|||||||
"dockerContainers": {
|
"dockerContainers": {
|
||||||
"name": "Docker stats",
|
"name": "Docker stats",
|
||||||
"description": "Stats of your containers (This widget can only be added with administrator privileges)",
|
"description": "Stats of your containers (This widget can only be added with administrator privileges)",
|
||||||
"option": {},
|
"option": {
|
||||||
|
"enableRowSorting": {
|
||||||
|
"label": "Enable items sorting"
|
||||||
|
},
|
||||||
|
"defaultSort": {
|
||||||
|
"label": "Column used for sorting by default",
|
||||||
|
"option": {
|
||||||
|
"name": "Name",
|
||||||
|
"state": "State",
|
||||||
|
"cpuUsage": "CPU usage",
|
||||||
|
"memoryUsage": "Memory usage"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"descendingDefaultSort": {
|
||||||
|
"label": "Invert sorting"
|
||||||
|
}
|
||||||
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"internalServerError": "Failed to fetch containers stats"
|
"internalServerError": "Failed to fetch containers stats"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -341,7 +341,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"full-all": {
|
"full-all": {
|
||||||
"label": "",
|
"label": "Acesso completo a aplicativos",
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,9 +35,9 @@
|
|||||||
"@mantine/hooks": "^8.3.9",
|
"@mantine/hooks": "^8.3.9",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"svgson": "^5.3.1"
|
"svgson": "^5.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -52,29 +52,29 @@
|
|||||||
"@mantine/core": "^8.3.9",
|
"@mantine/core": "^8.3.9",
|
||||||
"@mantine/hooks": "^8.3.9",
|
"@mantine/hooks": "^8.3.9",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"@tiptap/extension-color": "2.27.1",
|
"@tiptap/extension-color": "3.13.0",
|
||||||
"@tiptap/extension-highlight": "2.27.1",
|
"@tiptap/extension-highlight": "3.13.0",
|
||||||
"@tiptap/extension-image": "2.27.1",
|
"@tiptap/extension-image": "3.13.0",
|
||||||
"@tiptap/extension-link": "^2.27.1",
|
"@tiptap/extension-link": "^3.13.0",
|
||||||
"@tiptap/extension-placeholder": "^2.27.1",
|
"@tiptap/extension-placeholder": "^3.13.0",
|
||||||
"@tiptap/extension-table": "2.27.1",
|
"@tiptap/extension-table": "3.13.0",
|
||||||
"@tiptap/extension-table-cell": "2.27.1",
|
"@tiptap/extension-table-cell": "3.13.0",
|
||||||
"@tiptap/extension-table-header": "2.27.1",
|
"@tiptap/extension-table-header": "3.13.0",
|
||||||
"@tiptap/extension-table-row": "2.27.1",
|
"@tiptap/extension-table-row": "3.13.0",
|
||||||
"@tiptap/extension-task-item": "2.27.1",
|
"@tiptap/extension-task-item": "3.13.0",
|
||||||
"@tiptap/extension-task-list": "2.27.1",
|
"@tiptap/extension-task-list": "3.13.0",
|
||||||
"@tiptap/extension-text-align": "2.27.1",
|
"@tiptap/extension-text-align": "3.13.0",
|
||||||
"@tiptap/extension-text-style": "2.27.1",
|
"@tiptap/extension-text-style": "3.13.0",
|
||||||
"@tiptap/extension-underline": "2.27.1",
|
"@tiptap/extension-underline": "3.13.0",
|
||||||
"@tiptap/react": "^2.27.1",
|
"@tiptap/react": "^3.13.0",
|
||||||
"@tiptap/starter-kit": "^2.27.1",
|
"@tiptap/starter-kit": "^3.13.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"mantine-form-zod-resolver": "^1.3.0",
|
"mantine-form-zod-resolver": "^1.3.0",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.0.7",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"recharts": "^2.15.4",
|
"recharts": "^2.15.4",
|
||||||
"video.js": "^8.23.4",
|
"video.js": "^8.23.4",
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ const createColumns = (
|
|||||||
t: ReturnType<typeof useScopedI18n<"docker">>,
|
t: ReturnType<typeof useScopedI18n<"docker">>,
|
||||||
): MRT_ColumnDef<RouterOutputs["docker"]["getContainers"]["containers"][number]>[] => [
|
): MRT_ColumnDef<RouterOutputs["docker"]["getContainers"]["containers"][number]>[] => [
|
||||||
{
|
{
|
||||||
|
id: "name",
|
||||||
accessorKey: "name",
|
accessorKey: "name",
|
||||||
header: t("field.name.label"),
|
header: t("field.name.label"),
|
||||||
Cell({ renderedCellValue, row }) {
|
Cell({ renderedCellValue, row }) {
|
||||||
@@ -70,6 +71,7 @@ const createColumns = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "state",
|
||||||
accessorKey: "state",
|
accessorKey: "state",
|
||||||
size: 100,
|
size: 100,
|
||||||
header: t("field.state.label"),
|
header: t("field.state.label"),
|
||||||
@@ -78,6 +80,13 @@ const createColumns = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "cpuUsage",
|
||||||
|
sortingFn: (rowA, rowB) => {
|
||||||
|
const cpuUsageA = safeValue(rowA.original.cpuUsage);
|
||||||
|
const cpuUsageB = safeValue(rowB.original.cpuUsage);
|
||||||
|
|
||||||
|
return cpuUsageA - cpuUsageB;
|
||||||
|
},
|
||||||
accessorKey: "cpuUsage",
|
accessorKey: "cpuUsage",
|
||||||
size: 80,
|
size: 80,
|
||||||
header: t("field.stats.cpu.label"),
|
header: t("field.stats.cpu.label"),
|
||||||
@@ -92,6 +101,13 @@ const createColumns = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "memoryUsage",
|
||||||
|
sortingFn: (rowA, rowB) => {
|
||||||
|
const memoryUsageA = safeValue(rowA.original.memoryUsage);
|
||||||
|
const memoryUsageB = safeValue(rowB.original.memoryUsage);
|
||||||
|
|
||||||
|
return memoryUsageA - memoryUsageB;
|
||||||
|
},
|
||||||
accessorKey: "memoryUsage",
|
accessorKey: "memoryUsage",
|
||||||
size: 80,
|
size: 80,
|
||||||
header: t("field.stats.memory.label"),
|
header: t("field.stats.memory.label"),
|
||||||
@@ -106,9 +122,11 @@ const createColumns = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "actions",
|
||||||
accessorKey: "actions",
|
accessorKey: "actions",
|
||||||
size: 80,
|
size: 80,
|
||||||
header: t("action.title"),
|
header: t("action.title"),
|
||||||
|
enableSorting: false,
|
||||||
Cell({ row }) {
|
Cell({ row }) {
|
||||||
const utils = clientApi.useUtils();
|
const utils = clientApi.useUtils();
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
@@ -168,7 +186,7 @@ const createColumns = (
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function DockerWidget({ width }: WidgetComponentProps<"dockerContainers">) {
|
export default function DockerWidget({ options, width, isEditMode }: WidgetComponentProps<"dockerContainers">) {
|
||||||
const t = useScopedI18n("docker");
|
const t = useScopedI18n("docker");
|
||||||
const isTiny = width <= 256;
|
const isTiny = width <= 256;
|
||||||
|
|
||||||
@@ -192,8 +210,8 @@ export default function DockerWidget({ width }: WidgetComponentProps<"dockerCont
|
|||||||
enablePagination: false,
|
enablePagination: false,
|
||||||
enableTopToolbar: false,
|
enableTopToolbar: false,
|
||||||
enableBottomToolbar: false,
|
enableBottomToolbar: false,
|
||||||
enableSorting: false,
|
|
||||||
enableColumnActions: false,
|
enableColumnActions: false,
|
||||||
|
enableSorting: options.enableRowSorting && !isEditMode,
|
||||||
enableStickyHeader: false,
|
enableStickyHeader: false,
|
||||||
enableColumnOrdering: false,
|
enableColumnOrdering: false,
|
||||||
enableRowSelection: false,
|
enableRowSelection: false,
|
||||||
@@ -203,6 +221,7 @@ export default function DockerWidget({ width }: WidgetComponentProps<"dockerCont
|
|||||||
enableFilters: false,
|
enableFilters: false,
|
||||||
enableHiding: false,
|
enableHiding: false,
|
||||||
initialState: {
|
initialState: {
|
||||||
|
sorting: [{ id: options.defaultSort, desc: options.descendingDefaultSort }],
|
||||||
density: "xs",
|
density: "xs",
|
||||||
},
|
},
|
||||||
mantinePaperProps: {
|
mantinePaperProps: {
|
||||||
|
|||||||
@@ -1,12 +1,35 @@
|
|||||||
import { IconBrandDocker, IconServerOff } from "@tabler/icons-react";
|
import { IconBrandDocker, IconServerOff } from "@tabler/icons-react";
|
||||||
|
|
||||||
|
import type { RouterOutputs } from "@homarr/api";
|
||||||
|
|
||||||
import { createWidgetDefinition } from "../definition";
|
import { createWidgetDefinition } from "../definition";
|
||||||
import { optionsBuilder } from "../options";
|
import { optionsBuilder } from "../options";
|
||||||
|
|
||||||
|
const columnsList = [
|
||||||
|
"name",
|
||||||
|
"state",
|
||||||
|
"cpuUsage",
|
||||||
|
"memoryUsage",
|
||||||
|
] as const satisfies (keyof RouterOutputs["docker"]["getContainers"]["containers"][number])[];
|
||||||
|
|
||||||
export const { definition, componentLoader } = createWidgetDefinition("dockerContainers", {
|
export const { definition, componentLoader } = createWidgetDefinition("dockerContainers", {
|
||||||
icon: IconBrandDocker,
|
icon: IconBrandDocker,
|
||||||
createOptions() {
|
createOptions() {
|
||||||
return optionsBuilder.from(() => ({}));
|
return optionsBuilder.from((factory) => ({
|
||||||
|
enableRowSorting: factory.switch({
|
||||||
|
defaultValue: false,
|
||||||
|
}),
|
||||||
|
defaultSort: factory.select({
|
||||||
|
defaultValue: "name",
|
||||||
|
options: columnsList.map((value) => ({
|
||||||
|
value,
|
||||||
|
label: (t) => t(`widget.dockerContainers.option.defaultSort.option.${value}`),
|
||||||
|
})),
|
||||||
|
}),
|
||||||
|
descendingDefaultSort: factory.switch({
|
||||||
|
defaultValue: false,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
INTERNAL_SERVER_ERROR: {
|
INTERNAL_SERVER_ERROR: {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
IconX,
|
IconX,
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import relativeTime from "dayjs/plugin/relativeTime";
|
||||||
import type { MRT_ColumnDef, MRT_VisibilityState } from "mantine-react-table";
|
import type { MRT_ColumnDef, MRT_VisibilityState } from "mantine-react-table";
|
||||||
import { MantineReactTable, useMantineReactTable } from "mantine-react-table";
|
import { MantineReactTable, useMantineReactTable } from "mantine-react-table";
|
||||||
|
|
||||||
@@ -48,6 +49,8 @@ import { useScopedI18n } from "@homarr/translation/client";
|
|||||||
|
|
||||||
import type { WidgetComponentProps } from "../definition";
|
import type { WidgetComponentProps } from "../definition";
|
||||||
|
|
||||||
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
interface QuickFilter {
|
interface QuickFilter {
|
||||||
integrationKinds: string[];
|
integrationKinds: string[];
|
||||||
statuses: ExtendedDownloadClientItem["state"][];
|
statuses: ExtendedDownloadClientItem["state"][];
|
||||||
@@ -188,14 +191,14 @@ export default function DownloadClientsWidget({
|
|||||||
)
|
)
|
||||||
//Add extrapolated data and actions if user is allowed interaction
|
//Add extrapolated data and actions if user is allowed interaction
|
||||||
.map((item): ExtendedDownloadClientItem => {
|
.map((item): ExtendedDownloadClientItem => {
|
||||||
const received = Math.floor(item.size * item.progress);
|
const received = item.received ?? Math.floor(item.size * item.progress);
|
||||||
const integrationIds = [pair.integration.id];
|
const integrationIds = [pair.integration.id];
|
||||||
return {
|
return {
|
||||||
integration: pair.integration,
|
integration: pair.integration,
|
||||||
...item,
|
...item,
|
||||||
category: item.category !== undefined && item.category.length > 0 ? item.category : undefined,
|
category: item.category !== undefined && item.category.length > 0 ? item.category : undefined,
|
||||||
received,
|
received,
|
||||||
ratio: item.sent !== undefined ? item.sent / (received || 1) : undefined,
|
ratio: item.sent !== undefined ? item.sent / item.size : undefined,
|
||||||
//Only add if permission to use mutations
|
//Only add if permission to use mutations
|
||||||
actions: integrationsWithInteractions.includes(pair.integration.id)
|
actions: integrationsWithInteractions.includes(pair.integration.id)
|
||||||
? {
|
? {
|
||||||
@@ -714,7 +717,10 @@ const ItemInfoModal = ({ items, currentIndex, opened, onClose }: ItemInfoModalPr
|
|||||||
/>
|
/>
|
||||||
{item.type !== "miscellaneous" && <NormalizedLine itemKey="ratio" values={item.ratio} />}
|
{item.type !== "miscellaneous" && <NormalizedLine itemKey="ratio" values={item.ratio} />}
|
||||||
<NormalizedLine itemKey="added" values={item.added === undefined ? "unknown" : dayjs(item.added).format()} />
|
<NormalizedLine itemKey="added" values={item.added === undefined ? "unknown" : dayjs(item.added).format()} />
|
||||||
<NormalizedLine itemKey="time" values={item.time !== 0 ? dayjs().add(item.time).format() : "∞"} />
|
<NormalizedLine
|
||||||
|
itemKey="time"
|
||||||
|
values={item.time !== 0 ? dayjs().add(item.time, "milliseconds").fromNow() : "∞"}
|
||||||
|
/>
|
||||||
<NormalizedLine itemKey="category" values={item.category} />
|
<NormalizedLine itemKey="category" values={item.category} />
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -41,21 +41,21 @@ import {
|
|||||||
IconX,
|
IconX,
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import { Color } from "@tiptap/extension-color";
|
import { Color } from "@tiptap/extension-color";
|
||||||
import Highlight from "@tiptap/extension-highlight";
|
import { Highlight } from "@tiptap/extension-highlight";
|
||||||
import Image from "@tiptap/extension-image";
|
import { Image } from "@tiptap/extension-image";
|
||||||
import Placeholder from "@tiptap/extension-placeholder";
|
import { Placeholder } from "@tiptap/extension-placeholder";
|
||||||
import Table from "@tiptap/extension-table";
|
import { Table } from "@tiptap/extension-table";
|
||||||
import TableCell from "@tiptap/extension-table-cell";
|
import { TableCell } from "@tiptap/extension-table-cell";
|
||||||
import TableHeader from "@tiptap/extension-table-header";
|
import { TableHeader } from "@tiptap/extension-table-header";
|
||||||
import TableRow from "@tiptap/extension-table-row";
|
import { TableRow } from "@tiptap/extension-table-row";
|
||||||
import TaskItem from "@tiptap/extension-task-item";
|
import { TaskItem } from "@tiptap/extension-task-item";
|
||||||
import TaskList from "@tiptap/extension-task-list";
|
import { TaskList } from "@tiptap/extension-task-list";
|
||||||
import TextAlign from "@tiptap/extension-text-align";
|
import { TextAlign } from "@tiptap/extension-text-align";
|
||||||
import TextStyle from "@tiptap/extension-text-style";
|
import { TextStyle } from "@tiptap/extension-text-style";
|
||||||
import Underline from "@tiptap/extension-underline";
|
|
||||||
import type { Editor } from "@tiptap/react";
|
import type { Editor } from "@tiptap/react";
|
||||||
import { BubbleMenu, useEditor } from "@tiptap/react";
|
import { useEditor } from "@tiptap/react";
|
||||||
import StarterKit from "@tiptap/starter-kit";
|
import { BubbleMenu } from "@tiptap/react/menus";
|
||||||
|
import { StarterKit } from "@tiptap/starter-kit";
|
||||||
import type { Node } from "prosemirror-model";
|
import type { Node } from "prosemirror-model";
|
||||||
|
|
||||||
import { clientApi } from "@homarr/api/client";
|
import { clientApi } from "@homarr/api/client";
|
||||||
@@ -133,7 +133,8 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
StarterKit,
|
// we use a custom link implementation from mantine
|
||||||
|
StarterKit.configure({ link: false }),
|
||||||
Table.configure({
|
Table.configure({
|
||||||
resizable: true,
|
resizable: true,
|
||||||
lastColumnResizable: false,
|
lastColumnResizable: false,
|
||||||
@@ -170,8 +171,9 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W
|
|||||||
TaskList.configure({ itemTypeName: "taskItem" }),
|
TaskList.configure({ itemTypeName: "taskItem" }),
|
||||||
TextAlign.configure({ types: ["heading", "paragraph"] }),
|
TextAlign.configure({ types: ["heading", "paragraph"] }),
|
||||||
TextStyle,
|
TextStyle,
|
||||||
Underline,
|
|
||||||
],
|
],
|
||||||
|
shouldRerenderOnTransaction: true,
|
||||||
|
immediatelyRender: false,
|
||||||
content,
|
content,
|
||||||
onUpdate: ({ editor }) => {
|
onUpdate: ({ editor }) => {
|
||||||
setContent(editor.getHTML());
|
setContent(editor.getHTML());
|
||||||
|
|||||||
1965
pnpm-lock.yaml
generated
1965
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -5,4 +5,4 @@ packages:
|
|||||||
minimumReleaseAge: 4320 # Only download deps if they are at least 3 days old (in minutes)
|
minimumReleaseAge: 4320 # Only download deps if they are at least 3 days old (in minutes)
|
||||||
minimumReleaseAgeExclude:
|
minimumReleaseAgeExclude:
|
||||||
- next
|
- next
|
||||||
- "@next/eslint-plugin-next"
|
- "@next/*"
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Create sub directories in volume
|
# Create sub directories in volume
|
||||||
mkdir -p /appdata/db
|
mkdir -p /appdata/db
|
||||||
mkdir -p /appdata/redis
|
mkdir -p /appdata/redis
|
||||||
mkdir -p /appdata/trusted-certificates
|
mkdir -p /appdata/trusted-certificates
|
||||||
|
|
||||||
# Run migrations
|
# Run migrations
|
||||||
if [ $DB_MIGRATIONS_DISABLED = "true" ]; then
|
if [ "$DB_MIGRATIONS_DISABLED" = "true" ]; then
|
||||||
echo "DB migrations are disabled, skipping"
|
echo "DB migrations are disabled, skipping"
|
||||||
else
|
else
|
||||||
echo "Running DB migrations"
|
echo "Running DB migrations"
|
||||||
@@ -20,13 +22,15 @@ export CRON_JOB_API_KEY=$(openssl rand -base64 32)
|
|||||||
# 1. Replace the HOSTNAME in the nginx template file
|
# 1. Replace the HOSTNAME in the nginx template file
|
||||||
# 2. Create the nginx configuration file from the template
|
# 2. Create the nginx configuration file from the template
|
||||||
# 3. Start the nginx server
|
# 3. Start the nginx server
|
||||||
|
export HOSTNAME
|
||||||
envsubst '${HOSTNAME}' < /etc/nginx/templates/nginx.conf > /etc/nginx/nginx.conf
|
envsubst '${HOSTNAME}' < /etc/nginx/templates/nginx.conf > /etc/nginx/nginx.conf
|
||||||
# Start services in the background and store their PIDs
|
# Start services in the background and store their PIDs
|
||||||
nginx -g 'daemon off;' &
|
nginx -g 'daemon off;' &
|
||||||
NGINX_PID=$!
|
NGINX_PID=$!
|
||||||
|
|
||||||
if [ $REDIS_IS_EXTERNAL = "true" ]; then
|
if [ "$REDIS_IS_EXTERNAL" = "true" ]; then
|
||||||
echo "Using external Redis server at redis://$REDIS_HOST:$REDIS_PORT"
|
echo "Using external Redis server at redis://$REDIS_HOST:$REDIS_PORT"
|
||||||
|
REDIS_PID=""
|
||||||
else
|
else
|
||||||
echo "Starting internal Redis server"
|
echo "Starting internal Redis server"
|
||||||
redis-server /app/redis.conf &
|
redis-server /app/redis.conf &
|
||||||
@@ -49,9 +53,11 @@ terminate() {
|
|||||||
echo "Received SIGTERM. Shutting down..."
|
echo "Received SIGTERM. Shutting down..."
|
||||||
kill -TERM $NGINX_PID $TASKS_PID $WSS_PID $NEXTJS_PID 2>/dev/null
|
kill -TERM $NGINX_PID $TASKS_PID $WSS_PID $NEXTJS_PID 2>/dev/null
|
||||||
wait
|
wait
|
||||||
# kill redis-server last because of logging of other services
|
# kill redis-server last because of logging of other services and only if $REDIS_PID is set
|
||||||
kill -TERM $REDIS_PID 2>/dev/null
|
if [ -n "$REDIS_PID" ]; then
|
||||||
wait
|
kill -TERM $REDIS_PID 2>/dev/null
|
||||||
|
wait
|
||||||
|
fi
|
||||||
echo "Shutdown complete."
|
echo "Shutdown complete."
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
@@ -61,4 +67,4 @@ trap terminate TERM INT
|
|||||||
|
|
||||||
# Wait for all processes
|
# Wait for all processes
|
||||||
wait $NEXTJS_PID
|
wait $NEXTJS_PID
|
||||||
terminate
|
terminate
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -17,9 +17,9 @@
|
|||||||
},
|
},
|
||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/eslint-plugin-next": "16.0.7",
|
"@next/eslint-plugin-next": "16.0.10",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-config-turbo": "^2.6.1",
|
"eslint-config-turbo": "^2.6.3",
|
||||||
"eslint-plugin-import": "^2.32.0",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
|
|||||||
Reference in New Issue
Block a user