mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-25 06:49:18 +01:00
Compare commits
1 Commits
v0.17.1
...
tonya/lang
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
646a80f494 |
11
.github/scripts/update_currencies.py
vendored
11
.github/scripts/update_currencies.py
vendored
@@ -4,8 +4,11 @@ import os
|
||||
|
||||
def fetch_currencies():
|
||||
try:
|
||||
response = requests.get('https://restcountries.com/v3.1/all?fields=name,common,currencies')
|
||||
response = requests.get('https://restcountries.com/v3.1/all')
|
||||
response.raise_for_status()
|
||||
except requests.exceptions.Timeout:
|
||||
print("Request to the API timed out.")
|
||||
return []
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"An error occurred while making the request: {e}")
|
||||
return []
|
||||
@@ -32,12 +35,10 @@ def fetch_currencies():
|
||||
return currencies_list
|
||||
|
||||
def save_currencies(currencies, file_path):
|
||||
# Sort the list by the "local" field
|
||||
sorted_currencies = sorted(currencies, key=lambda x: x['local'].lower() if x['local'] else "")
|
||||
try:
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(sorted_currencies, f, ensure_ascii=False, indent=4)
|
||||
json.dump(currencies, f, ensure_ascii=False, indent=4)
|
||||
except IOError as e:
|
||||
print(f"An error occurred while writing to the file: {e}")
|
||||
|
||||
@@ -61,4 +62,4 @@ def main():
|
||||
print("Currencies updated and saved.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
25
.github/workflows/clear-stale-docker-images.yml
vendored
25
.github/workflows/clear-stale-docker-images.yml
vendored
@@ -1,25 +0,0 @@
|
||||
name: Docker Cleanup
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '00 0 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
delete-untagged-images:
|
||||
name: Delete Untagged Images
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
steps:
|
||||
- uses: dataaxiom/ghcr-cleanup-action@v1
|
||||
with:
|
||||
dry-run: false
|
||||
package: homebox
|
||||
delete-ghost-images: true
|
||||
delete-orphaned-images: true
|
||||
delete-partial-images: true
|
||||
delete-untagged: true
|
||||
# Make sure to update this to include the latest major tags
|
||||
exclude-tags: main,vnext,latest,0.*,1.*
|
||||
older-than: 3 months
|
||||
105
.github/workflows/docker-publish-arm.yaml
vendored
Normal file
105
.github/workflows/docker-publish-arm.yaml
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
name: Docker publish ARM
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '00 0 * * *'
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- 'backend/**'
|
||||
- 'frontend/**'
|
||||
- 'Dockerfile'
|
||||
- 'Dockerfile.rootless'
|
||||
- '.dockerignore'
|
||||
- '.github/workflows'
|
||||
# Publish semver tags as releases.
|
||||
tags: [ 'v*.*.*' ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- 'backend/**'
|
||||
- 'frontend/**'
|
||||
- 'Dockerfile'
|
||||
- 'Dockerfile.rootless'
|
||||
- '.dockerignore'
|
||||
- '.github/workflows'
|
||||
|
||||
env:
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: ghcr.io
|
||||
# github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
attestations: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
# Step 1: Checkout repository
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Step 2: Set up Buildx without specifying driver
|
||||
# Let it use default settings to avoid the 'no remote endpoint' issue
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.0.0
|
||||
with:
|
||||
install: true # Ensure Buildx is installed and set up properly
|
||||
use: true # Use Buildx instance directly for this job
|
||||
|
||||
# Step 3: Login against Docker registry except on PR
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3.0.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Step 4: Extract metadata for Docker images
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5.0.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=schedule,pattern=nightly
|
||||
flavor: |
|
||||
suffix=-arm,onlatest=true
|
||||
|
||||
# Step 5: Build and push the Docker image
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: linux/arm64,linux/arm/v7
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
COMMIT=${{ github.sha }}
|
||||
|
||||
# Step 6: Attest built image to prove build provenance
|
||||
- name: Attest
|
||||
uses: actions/attest-build-provenance@v1
|
||||
id: attest
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
with:
|
||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
subject-digest: ${{ steps.build-and-push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
104
.github/workflows/docker-publish-rootless-arm.yaml
vendored
Normal file
104
.github/workflows/docker-publish-rootless-arm.yaml
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
name: Docker publish rootless ARM
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '00 0 * * *'
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- 'backend/**'
|
||||
- 'frontend/**'
|
||||
- 'Dockerfile'
|
||||
- 'Dockerfile.rootless'
|
||||
- '.dockerignore'
|
||||
- '.github/workflows'
|
||||
# Publish semver tags as releases.
|
||||
tags: [ 'v*.*.*' ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- 'backend/**'
|
||||
- 'frontend/**'
|
||||
- 'Dockerfile'
|
||||
- 'Dockerfile.rootless'
|
||||
- '.dockerignore'
|
||||
- '.github/workflows'
|
||||
|
||||
env:
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: ghcr.io
|
||||
# github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-rootless:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
attestations: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
# Step 1: Checkout repository
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Step 2: Set up Buildx without specifying driver
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.0.0
|
||||
with:
|
||||
install: true # Ensure Buildx is installed and set up properly
|
||||
use: true # Use Buildx instance directly for this job
|
||||
|
||||
# Step 3: Login to Docker registry except on PR
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3.0.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Step 4: Extract metadata for Docker images
|
||||
- name: Extract Docker metadata
|
||||
id: metadata
|
||||
uses: docker/metadata-action@v5.0.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=schedule,pattern=nightly
|
||||
flavor: |
|
||||
suffix=-rootless-arm,onlatest=true
|
||||
|
||||
# Step 5: Build and push the Docker image
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.metadata.outputs.tags }}
|
||||
labels: ${{ steps.metadata.outputs.labels }}
|
||||
platforms: linux/arm64,linux/arm/v7
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
COMMIT=${{ github.sha }}
|
||||
|
||||
# Step 6: Attest built image to prove build provenance
|
||||
- name: Attest
|
||||
uses: actions/attest-build-provenance@v1
|
||||
id: attest
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
with:
|
||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
subject-digest: ${{ steps.build-and-push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
188
.github/workflows/docker-publish-rootless.yaml
vendored
188
.github/workflows/docker-publish-rootless.yaml
vendored
@@ -11,7 +11,8 @@ on:
|
||||
- 'Dockerfile'
|
||||
- 'Dockerfile.rootless'
|
||||
- '.dockerignore'
|
||||
- '.github/workflows/**'
|
||||
- '.github/workflows'
|
||||
# Publish semver tags as releases.
|
||||
tags: [ 'v*.*.*' ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
@@ -21,145 +22,55 @@ on:
|
||||
- 'Dockerfile'
|
||||
- 'Dockerfile.rootless'
|
||||
- '.dockerignore'
|
||||
- '.github/workflows/**'
|
||||
- '.github/workflows'
|
||||
|
||||
|
||||
env:
|
||||
DOCKERHUB_REPO: sysadminsmedia/homebox
|
||||
GHCR_REPO: ghcr.io/sysadminsmedia/homebox
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: ghcr.io
|
||||
# github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-rootless:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
# This is used to complete the identity challenge
|
||||
# with sigstore/fulcio when running outside of PRs.
|
||||
attestations: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
- linux/arm/v7
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
branch=${{ github.event.pull_request.number || github.ref_name }}
|
||||
echo "BRANCH=${branch//\//-}" >> $GITHUB_ENV
|
||||
# Set up BuildKit Docker container builder to be able to build
|
||||
# multi-platform images and export cache
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.0.0 # v3.0.0
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3.0.0 # v3.0.0
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKERHUB_REPO }}
|
||||
${{ env.GHCR_REPO }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
# Extract metadata (tags, labels) for Docker
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: metadata
|
||||
uses: docker/metadata-action@v5.0.0 # v5.0.0
|
||||
with:
|
||||
image: ghcr.io/amitie10g/binfmt:latest
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver-opts: |
|
||||
image=ghcr.io/amitie10g/buildkit:master
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: . # Explicitly specify the build context
|
||||
file: ./Dockerfile.rootless # Explicitly specify the Dockerfile
|
||||
platforms: ${{ matrix.platform }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
||||
cache-from: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}-rootless
|
||||
cache-to: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}-rootless,mode=max
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
COMMIT=${{ github.sha }}
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
needs:
|
||||
- build
|
||||
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver-opts: |
|
||||
image=ghcr.io/amitie10g/buildkit:master
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKERHUB_REPO }}
|
||||
${{ env.GHCR_REPO }}
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
@@ -169,16 +80,29 @@ jobs:
|
||||
type=schedule,pattern=nightly
|
||||
flavor: |
|
||||
suffix=-rootless,onlatest=true
|
||||
|
||||
# Build and push Docker image with Buildx (don't push on PR)
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v5.0.0 # v5.0.0
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.metadata.outputs.tags }}
|
||||
labels: ${{ steps.metadata.outputs.labels }}
|
||||
platforms: linux/amd64
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
COMMIT=${{ github.sha }}
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *)
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf '${{ env.GHCR_REPO }}@sha256:%s ' *)
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.DOCKERHUB_REPO }}:${{ steps.meta.outputs.version }}
|
||||
docker buildx imagetools inspect ${{ env.GHCR_REPO }}:${{ steps.meta.outputs.version }}
|
||||
- name: Attest
|
||||
uses: actions/attest-build-provenance@v1
|
||||
id: attest
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
with:
|
||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
subject-digest: ${{ steps.build-and-push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
|
||||
189
.github/workflows/docker-publish.yaml
vendored
189
.github/workflows/docker-publish.yaml
vendored
@@ -9,8 +9,10 @@ on:
|
||||
- 'backend/**'
|
||||
- 'frontend/**'
|
||||
- 'Dockerfile'
|
||||
- 'Dockerfile.rootless'
|
||||
- '.dockerignore'
|
||||
- '.github/workflows/**'
|
||||
- '.github/workflows'
|
||||
# Publish semver tags as releases.
|
||||
tags: [ 'v*.*.*' ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
@@ -18,144 +20,56 @@ on:
|
||||
- 'backend/**'
|
||||
- 'frontend/**'
|
||||
- 'Dockerfile'
|
||||
- 'Dockerfile.rootless'
|
||||
- '.dockerignore'
|
||||
- '.github/workflows/**'
|
||||
- '.github/workflows'
|
||||
|
||||
env:
|
||||
DOCKERHUB_REPO: sysadminsmedia/homebox
|
||||
GHCR_REPO: ghcr.io/sysadminsmedia/homebox
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: ghcr.io
|
||||
# github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read # Allows access to repository contents (read-only)
|
||||
packages: write # Allows pushing to GHCR
|
||||
id-token: write # Allows identity token write access for authentication
|
||||
attestations: write # Needed for signing and attestation (if required)
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
- linux/arm/v7
|
||||
contents: read
|
||||
packages: write
|
||||
# This is used to complete the identity challenge
|
||||
# with sigstore/fulcio when running outside of PRs.
|
||||
attestations: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
branch=${{ github.event.pull_request.number || github.ref_name }}
|
||||
echo "BRANCH=${branch//\//-}" >> $GITHUB_ENV
|
||||
# Set up BuildKit Docker container builder to be able to build
|
||||
# multi-platform images and export cache
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.0.0 # v3.0.0
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3.0.0 # v3.0.0
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKERHUB_REPO }}
|
||||
${{ env.GHCR_REPO }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
image: ghcr.io/amitie10g/binfmt:latest
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver-opts: |
|
||||
image=ghcr.io/amitie10g/buildkit:master
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: ${{ matrix.platform }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
||||
cache-from: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}
|
||||
cache-to: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR}}-${{ env.BRANCH }},mode=max
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
COMMIT=${{ github.sha }}
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read # Allows access to repository contents (read-only)
|
||||
packages: write # Allows pushing to GHCR
|
||||
id-token: write # Allows identity token write access for authentication
|
||||
attestations: write # Needed for signing and attestation (if required)
|
||||
needs:
|
||||
- build
|
||||
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver-opts: |
|
||||
image=ghcr.io/amitie10g/buildkit:master
|
||||
|
||||
- name: Docker meta
|
||||
# Extract metadata (tags, labels) for Docker
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v5.0.0 # v5.0.0
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKERHUB_REPO }}
|
||||
${{ env.GHCR_REPO }}
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
@@ -164,15 +78,28 @@ jobs:
|
||||
type=semver,pattern={{major}}
|
||||
type=schedule,pattern=nightly
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *)
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf '${{ env.GHCR_REPO }}@sha256:%s ' *)
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.DOCKERHUB_REPO }}:${{ steps.meta.outputs.version }}
|
||||
docker buildx imagetools inspect ${{ env.GHCR_REPO }}:${{ steps.meta.outputs.version }}
|
||||
# Build and push Docker image with Buildx (don't push on PR)
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v5.0.0 # v5.0.0
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: linux/amd64
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
COMMIT=${{ github.sha }}
|
||||
|
||||
- name: Attest
|
||||
uses: actions/attest-build-provenance@v1
|
||||
id: attest
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
with:
|
||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
subject-digest: ${{ steps.build-and-push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
|
||||
5
.github/workflows/partial-backend.yaml
vendored
5
.github/workflows/partial-backend.yaml
vendored
@@ -34,8 +34,3 @@ jobs:
|
||||
|
||||
- name: Test
|
||||
run: task go:coverage
|
||||
|
||||
- name: Validate OpenAPI definition
|
||||
uses: swaggerexpert/swagger-editor-validate@v1
|
||||
with:
|
||||
definition-file: backend/app/api/static/docs/swagger.json
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -33,7 +33,7 @@ go.work
|
||||
backend/.env
|
||||
build/*
|
||||
|
||||
# Output Directory for Nuxt/Frontend during build steps
|
||||
# Output Directory for Nuxt/Frontend during build step
|
||||
backend/app/api/public/*
|
||||
!backend/app/api/public/.gitkeep
|
||||
|
||||
@@ -56,5 +56,4 @@ backend/app/api/static/public/*
|
||||
!backend/app/api/static/public/.gitkeep
|
||||
backend/api
|
||||
|
||||
docs/.vitepress/cache/
|
||||
/.data/
|
||||
docs/.vitepress/cache/
|
||||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -23,7 +23,7 @@
|
||||
"HBOX_LOG_LEVEL": "debug",
|
||||
"HBOX_DEBUG_ENABLED": "true",
|
||||
"HBOX_STORAGE_DATA": "${workspaceRoot}/backend/.data",
|
||||
"HBOX_STORAGE_SQLITE_URL": "${workspaceRoot}/backend/.data/homebox.db?_fk=1&_time_format=sqlite"
|
||||
"HBOX_STORAGE_SQLITE_URL": "${workspaceRoot}/backend/.data/homebox.db?_fk=1"
|
||||
},
|
||||
"console": "integratedTerminal",
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@ start command `task go:run`
|
||||
|
||||
### Frontend Development Notes
|
||||
|
||||
start command `task ui:dev`
|
||||
start command `task: ui:dev`
|
||||
|
||||
1. The frontend is a Vue 3 app with Nuxt.js that uses Tailwind and DaisyUI for styling.
|
||||
2. We're using Vitest for our automated testing. You can run these with `task ui:watch`.
|
||||
@@ -54,4 +54,4 @@ start command `task ui:dev`
|
||||
|
||||
Create a new tag in GitHub with the version number vX.X.X. This will trigger a new release to be created.
|
||||
|
||||
Test -> Goreleaser -> Publish Release -> Trigger Docker Builds -> Deploy Docs + Fly.io Demo
|
||||
Test -> Goreleaser -> Publish Release -> Trigger Docker Builds -> Deploy Docs + Fly.io Demo
|
||||
14
Dockerfile
14
Dockerfile
@@ -1,5 +1,5 @@
|
||||
# Node dependencies stage
|
||||
FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-dependencies
|
||||
FROM --platform=$TARGETPLATFORM node:18-alpine AS frontend-dependencies
|
||||
WORKDIR /app
|
||||
|
||||
# Install pnpm globally (caching layer)
|
||||
@@ -10,7 +10,7 @@ COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile --shamefully-hoist
|
||||
|
||||
# Build Nuxt (frontend) stage
|
||||
FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-builder
|
||||
FROM --platform=$TARGETPLATFORM node:18-alpine AS frontend-builder
|
||||
WORKDIR /app
|
||||
|
||||
# Install pnpm globally again (it can reuse the cache if not changed)
|
||||
@@ -22,7 +22,7 @@ COPY --from=frontend-dependencies /app/node_modules ./node_modules
|
||||
RUN pnpm build
|
||||
|
||||
# Go dependencies stage
|
||||
FROM public.ecr.aws/docker/library/golang:alpine AS builder-dependencies
|
||||
FROM --platform=$TARGETPLATFORM golang:alpine AS builder-dependencies
|
||||
WORKDIR /go/src/app
|
||||
|
||||
# Copy go.mod and go.sum for better caching
|
||||
@@ -30,7 +30,7 @@ COPY ./backend/go.mod ./backend/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Build API stage
|
||||
FROM public.ecr.aws/docker/library/golang:alpine AS builder
|
||||
FROM --platform=$TARGETPLATFORM golang:alpine AS builder
|
||||
ARG BUILD_TIME
|
||||
ARG COMMIT
|
||||
ARG VERSION
|
||||
@@ -58,10 +58,10 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
-v ./app/api/*.go
|
||||
|
||||
# Production stage
|
||||
FROM public.ecr.aws/docker/library/alpine:latest
|
||||
FROM --platform=$TARGETPLATFORM alpine:latest
|
||||
ENV HBOX_MODE=production
|
||||
ENV HBOX_STORAGE_DATA=/data/
|
||||
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1&_time_format=sqlite
|
||||
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1
|
||||
|
||||
# Install necessary runtime dependencies
|
||||
RUN apk --no-cache add ca-certificates wget
|
||||
@@ -75,7 +75,7 @@ RUN chmod +x /app/api
|
||||
LABEL Name=homebox Version=0.0.1
|
||||
LABEL org.opencontainers.image.source="https://github.com/sysadminsmedia/homebox"
|
||||
|
||||
# Expose necessary ports for Homebox
|
||||
# Expose necessary ports
|
||||
EXPOSE 7745
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
@@ -1,96 +1,73 @@
|
||||
# Node dependencies stage
|
||||
FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-dependencies
|
||||
# Node dependencies
|
||||
FROM node:18-alpine AS frontend-dependencies
|
||||
WORKDIR /app
|
||||
|
||||
# Install pnpm globally (caching layer)
|
||||
RUN npm install -g pnpm
|
||||
|
||||
# Copy package.json and lockfile to leverage caching
|
||||
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile --shamefully-hoist
|
||||
|
||||
# Build Nuxt (frontend) stage
|
||||
FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-builder
|
||||
# Build Nuxt
|
||||
FROM node:18-alpine AS frontend-builder
|
||||
WORKDIR /app
|
||||
|
||||
# Install pnpm globally again (it can reuse the cache if not changed)
|
||||
RUN npm install -g pnpm
|
||||
|
||||
# Copy over source files and node_modules from dependencies stage
|
||||
COPY frontend .
|
||||
COPY frontend ./
|
||||
COPY --from=frontend-dependencies /app/node_modules ./node_modules
|
||||
RUN pnpm build
|
||||
|
||||
# Go dependencies stage
|
||||
FROM public.ecr.aws/docker/library/golang:alpine AS builder-dependencies
|
||||
# Build Go dependencies
|
||||
FROM golang:alpine AS builder-dependencies
|
||||
WORKDIR /go/src/app
|
||||
|
||||
# Copy go.mod and go.sum for better caching
|
||||
COPY ./backend/go.mod ./backend/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Build API stage
|
||||
FROM public.ecr.aws/docker/library/golang:alpine AS builder
|
||||
# Build API
|
||||
FROM golang:alpine AS builder
|
||||
ARG BUILD_TIME
|
||||
ARG COMMIT
|
||||
ARG VERSION
|
||||
|
||||
# Install necessary build tools
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add --no-cache git build-base gcc g++
|
||||
RUN apk update && apk upgrade && apk add --no-cache git build-base gcc g++
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
# Copy Go modules (from dependencies stage) and source code
|
||||
COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod
|
||||
COPY ./backend .
|
||||
|
||||
# Clear old public files and copy new ones from frontend build
|
||||
RUN rm -rf ./app/api/public
|
||||
COPY --from=frontend-builder /app/.output/public ./app/api/static/public
|
||||
COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod
|
||||
|
||||
# Use cache for Go build artifacts
|
||||
# Use cache for Go build
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
CGO_ENABLED=0 GOOS=linux go build \
|
||||
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
||||
-o /go/bin/api \
|
||||
-v ./app/api/*.go
|
||||
-o /go/bin/api ./app/api/*.go
|
||||
|
||||
RUN mkdir /data
|
||||
# Production stage with distroless
|
||||
FROM gcr.io/distroless/static:latest
|
||||
|
||||
# Production stage
|
||||
FROM public.ecr.aws/docker/library/alpine:latest
|
||||
ENV HBOX_MODE=production
|
||||
ENV HBOX_STORAGE_DATA=/data/
|
||||
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1&_time_format=sqlite
|
||||
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1
|
||||
|
||||
# Install necessary runtime dependencies
|
||||
RUN apk --no-cache add ca-certificates wget
|
||||
RUN addgroup -S nonroot && adduser -S nonroot -G nonroot
|
||||
|
||||
# Create application directory and copy over built Go binary
|
||||
RUN mkdir /app
|
||||
# Copy the binary and data directory, change ownership
|
||||
COPY --from=builder --chown=nonroot /go/bin/api /app
|
||||
COPY --from=builder --chown=nonroot /data /data
|
||||
RUN chmod +x /app/api
|
||||
|
||||
# Labels and configuration for the final image
|
||||
# Add wget to the image
|
||||
# Note: If using distroless, this may not be applicable
|
||||
# as distroless images do not include package managers.
|
||||
# This line may be omitted if you're relying on another way to handle healthchecks.
|
||||
COPY --from=alpine:latest /bin/wget /usr/bin/wget
|
||||
|
||||
LABEL Name=homebox Version=0.0.1
|
||||
LABEL org.opencontainers.image.source="https://github.com/sysadminsmedia/homebox"
|
||||
|
||||
# Expose necessary ports for Homebox
|
||||
EXPOSE 7745
|
||||
WORKDIR /app
|
||||
|
||||
# Healthcheck configuration
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
||||
CMD [ "wget", "--no-verbose", "--tries=1", "-O", "-", "http://localhost:7745/api/v1/status" ]
|
||||
HEALTHCHECK --interval=30s \
|
||||
--timeout=5s \
|
||||
--start-period=5s \
|
||||
--retries=3 \
|
||||
CMD ["/usr/bin/wget", "--no-verbose", "--tries=1", "-O", "-", "http://localhost:7745/api/v1/status"]
|
||||
|
||||
# Persist volume
|
||||
VOLUME [ "/data" ]
|
||||
VOLUME ["/data"]
|
||||
|
||||
# Entrypoint and CMD
|
||||
# Drop root and run as a low-privileged user
|
||||
USER nonroot
|
||||
ENTRYPOINT [ "/app/api" ]
|
||||
CMD [ "/data/config.yml" ]
|
||||
ENTRYPOINT ["/app"]
|
||||
CMD ["/data/config.yml"]
|
||||
|
||||
@@ -21,10 +21,6 @@ Homebox is the inventory and organization system built for the Home User! With a
|
||||
|
||||
# Screenshots
|
||||
Check out screenshots of the project [here](https://imgur.com/a/5gLWt2j).
|
||||
You can also try the demo instances of Homebox:
|
||||
- [Demo](https://demo.homebox.software)
|
||||
- [Nightly](https://nightly.homebox.software)
|
||||
- [VNext](https://vnext.homebox.software/)
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ version: "3"
|
||||
|
||||
env:
|
||||
HBOX_LOG_LEVEL: debug
|
||||
HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1&_time_format=sqlite
|
||||
HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1
|
||||
HBOX_OPTIONS_ALLOW_REGISTRATION: true
|
||||
UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure"
|
||||
tasks:
|
||||
@@ -28,6 +28,7 @@ tasks:
|
||||
- "./backend/internal/data/**"
|
||||
- "./backend/internal/core/services/**/*"
|
||||
- "./backend/app/tools/typegen/main.go"
|
||||
|
||||
typescript-types:
|
||||
desc: Generates typescript types from swagger definition
|
||||
cmds:
|
||||
@@ -51,8 +52,6 @@ tasks:
|
||||
- cp ./backend/app/api/static/docs/swagger.json docs/docs/api/openapi-2.0.json
|
||||
|
||||
go:run:
|
||||
env:
|
||||
HBOX_DEMO: true
|
||||
desc: Starts the backend api server (depends on generate task)
|
||||
dir: backend
|
||||
deps:
|
||||
|
||||
@@ -23,9 +23,8 @@ func NewTask(name string, interval time.Duration, fn func(context.Context)) *Bac
|
||||
}
|
||||
|
||||
func (tsk *BackgroundTask) Start(ctx context.Context) error {
|
||||
tsk.Fn(ctx)
|
||||
|
||||
timer := time.NewTimer(tsk.Interval)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
||||
@@ -84,14 +84,13 @@ type (
|
||||
}
|
||||
|
||||
APISummary struct {
|
||||
Healthy bool `json:"health"`
|
||||
Versions []string `json:"versions"`
|
||||
Title string `json:"title"`
|
||||
Message string `json:"message"`
|
||||
Build Build `json:"build"`
|
||||
Latest services.Latest `json:"latest"`
|
||||
Demo bool `json:"demo"`
|
||||
AllowRegistration bool `json:"allowRegistration"`
|
||||
Healthy bool `json:"health"`
|
||||
Versions []string `json:"versions"`
|
||||
Title string `json:"title"`
|
||||
Message string `json:"message"`
|
||||
Build Build `json:"build"`
|
||||
Demo bool `json:"demo"`
|
||||
AllowRegistration bool `json:"allowRegistration"`
|
||||
}
|
||||
)
|
||||
|
||||
@@ -112,11 +111,11 @@ func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, bus *event
|
||||
|
||||
// HandleBase godoc
|
||||
//
|
||||
// @Summary Application Info
|
||||
// @Tags Base
|
||||
// @Produce json
|
||||
// @Success 200 {object} APISummary
|
||||
// @Router /v1/status [GET]
|
||||
// @Summary Application Info
|
||||
// @Tags Base
|
||||
// @Produce json
|
||||
// @Success 200 {object} APISummary
|
||||
// @Router /v1/status [GET]
|
||||
func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
return server.JSON(w, http.StatusOK, APISummary{
|
||||
@@ -124,7 +123,6 @@ func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.Hand
|
||||
Title: "Homebox",
|
||||
Message: "Track, Manage, and Organize your Things",
|
||||
Build: build,
|
||||
Latest: ctrl.svc.BackgroundService.GetLatestVersion(),
|
||||
Demo: ctrl.isDemo,
|
||||
AllowRegistration: ctrl.allowRegistration,
|
||||
})
|
||||
@@ -133,11 +131,11 @@ func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.Hand
|
||||
|
||||
// HandleCurrency godoc
|
||||
//
|
||||
// @Summary Currency
|
||||
// @Tags Base
|
||||
// @Produce json
|
||||
// @Success 200 {object} currencies.Currency
|
||||
// @Router /v1/currency [GET]
|
||||
// @Summary Currency
|
||||
// @Tags Base
|
||||
// @Produce json
|
||||
// @Success 200 {object} currencies.Currency
|
||||
// @Router /v1/currency [GET]
|
||||
func (ctrl *V1Controller) HandleCurrency() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
// Set Cache for 10 Minutes
|
||||
|
||||
@@ -32,52 +32,52 @@ func actionHandlerFactory(ref string, fn func(context.Context, uuid.UUID) (int,
|
||||
|
||||
// HandleEnsureAssetID godoc
|
||||
//
|
||||
// @Summary Ensure Asset IDs
|
||||
// @Description Ensures all items in the database have an asset ID
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/ensure-asset-ids [Post]
|
||||
// @Security Bearer
|
||||
// @Summary Ensure Asset IDs
|
||||
// @Description Ensures all items in the database have an asset ID
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/ensure-asset-ids [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleEnsureAssetID() errchain.HandlerFunc {
|
||||
return actionHandlerFactory("ensure asset IDs", ctrl.svc.Items.EnsureAssetID)
|
||||
}
|
||||
|
||||
// HandleEnsureImportRefs godoc
|
||||
//
|
||||
// @Summary Ensures Import Refs
|
||||
// @Description Ensures all items in the database have an import ref
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/ensure-import-refs [Post]
|
||||
// @Security Bearer
|
||||
// @Summary Ensures Import Refs
|
||||
// @Description Ensures all items in the database have an import ref
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/ensure-import-refs [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleEnsureImportRefs() errchain.HandlerFunc {
|
||||
return actionHandlerFactory("ensure import refs", ctrl.svc.Items.EnsureImportRef)
|
||||
}
|
||||
|
||||
// HandleItemDateZeroOut godoc
|
||||
//
|
||||
// @Summary Zero Out Time Fields
|
||||
// @Description Resets all item date fields to the beginning of the day
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/zero-item-time-fields [Post]
|
||||
// @Security Bearer
|
||||
// @Summary Zero Out Time Fields
|
||||
// @Description Resets all item date fields to the beginning of the day
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/zero-item-time-fields [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemDateZeroOut() errchain.HandlerFunc {
|
||||
return actionHandlerFactory("zero out date time", ctrl.repo.Items.ZeroOutTimeFields)
|
||||
}
|
||||
|
||||
// HandleSetPrimaryPhotos godoc
|
||||
//
|
||||
// @Summary Set Primary Photos
|
||||
// @Description Sets the first photo of each item as the primary photo
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/set-primary-photos [Post]
|
||||
// @Security Bearer
|
||||
// @Summary Set Primary Photos
|
||||
// @Description Sets the first photo of each item as the primary photo
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/set-primary-photos [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleSetPrimaryPhotos() errchain.HandlerFunc {
|
||||
return actionHandlerFactory("ensure asset IDs", ctrl.repo.Items.SetPrimaryPhotos)
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@ import (
|
||||
|
||||
// HandleAssetGet godocs
|
||||
//
|
||||
// @Summary Get Item by Asset ID
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Asset ID"
|
||||
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
|
||||
// @Router /v1/assets/{id} [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Item by Asset ID
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Asset ID"
|
||||
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
|
||||
// @Router /v1/assets/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAssetGet() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
|
||||
@@ -28,8 +28,8 @@ type (
|
||||
}
|
||||
|
||||
LoginForm struct {
|
||||
Username string `json:"username" example:"admin@admin.com"`
|
||||
Password string `json:"password" example:"admin"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
StayLoggedIn bool `json:"stayLoggedIn"`
|
||||
}
|
||||
)
|
||||
@@ -83,6 +83,8 @@ type AuthProvider interface {
|
||||
// @Tags Authentication
|
||||
// @Accept x-www-form-urlencoded
|
||||
// @Accept application/json
|
||||
// @Param username formData string false "string" example(admin@admin.com)
|
||||
// @Param password formData string false "string" example(admin)
|
||||
// @Param payload body LoginForm true "Login Data"
|
||||
// @Param provider query string false "auth provider"
|
||||
// @Produce json
|
||||
@@ -129,11 +131,11 @@ func (ctrl *V1Controller) HandleAuthLogin(ps ...AuthProvider) errchain.HandlerFu
|
||||
|
||||
// HandleAuthLogout godoc
|
||||
//
|
||||
// @Summary User Logout
|
||||
// @Tags Authentication
|
||||
// @Success 204
|
||||
// @Router /v1/users/logout [POST]
|
||||
// @Security Bearer
|
||||
// @Summary User Logout
|
||||
// @Tags Authentication
|
||||
// @Success 204
|
||||
// @Router /v1/users/logout [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAuthLogout() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
token := services.UseTokenCtx(r.Context())
|
||||
@@ -153,13 +155,13 @@ func (ctrl *V1Controller) HandleAuthLogout() errchain.HandlerFunc {
|
||||
|
||||
// HandleAuthRefresh godoc
|
||||
//
|
||||
// @Summary User Token Refresh
|
||||
// @Description handleAuthRefresh returns a handler that will issue a new token from an existing token.
|
||||
// @Description This does not validate that the user still exists within the database.
|
||||
// @Tags Authentication
|
||||
// @Success 200
|
||||
// @Router /v1/users/refresh [GET]
|
||||
// @Security Bearer
|
||||
// @Summary User Token Refresh
|
||||
// @Description handleAuthRefresh returns a handler that will issue a new token from an existing token.
|
||||
// @Description This does not validate that the user still exists within the database.
|
||||
// @Tags Authentication
|
||||
// @Success 200
|
||||
// @Router /v1/users/refresh [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAuthRefresh() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
requestToken := services.UseTokenCtx(r.Context())
|
||||
|
||||
@@ -26,12 +26,12 @@ type (
|
||||
|
||||
// HandleGroupGet godoc
|
||||
//
|
||||
// @Summary Get Group
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.Group
|
||||
// @Router /v1/groups [Get]
|
||||
// @Security Bearer
|
||||
// @Summary Get Group
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.Group
|
||||
// @Router /v1/groups [Get]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupGet() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) (repo.Group, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -43,13 +43,13 @@ func (ctrl *V1Controller) HandleGroupGet() errchain.HandlerFunc {
|
||||
|
||||
// HandleGroupUpdate godoc
|
||||
//
|
||||
// @Summary Update Group
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Param payload body repo.GroupUpdate true "User Data"
|
||||
// @Success 200 {object} repo.Group
|
||||
// @Router /v1/groups [Put]
|
||||
// @Security Bearer
|
||||
// @Summary Update Group
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Param payload body repo.GroupUpdate true "User Data"
|
||||
// @Success 200 {object} repo.Group
|
||||
// @Router /v1/groups [Put]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupUpdate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, body repo.GroupUpdate) (repo.Group, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -69,13 +69,13 @@ func (ctrl *V1Controller) HandleGroupUpdate() errchain.HandlerFunc {
|
||||
|
||||
// HandleGroupInvitationsCreate godoc
|
||||
//
|
||||
// @Summary Create Group Invitation
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Param payload body GroupInvitationCreate true "User Data"
|
||||
// @Success 200 {object} GroupInvitation
|
||||
// @Router /v1/groups/invitations [Post]
|
||||
// @Security Bearer
|
||||
// @Summary Create Group Invitation
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Param payload body GroupInvitationCreate true "User Data"
|
||||
// @Success 200 {object} GroupInvitation
|
||||
// @Router /v1/groups/invitations [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupInvitationsCreate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, body GroupInvitationCreate) (GroupInvitation, error) {
|
||||
if body.ExpiresAt.IsZero() {
|
||||
|
||||
@@ -4,12 +4,10 @@ import (
|
||||
"database/sql"
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/httpkit/errchain"
|
||||
@@ -23,18 +21,18 @@ import (
|
||||
|
||||
// HandleItemsGetAll godoc
|
||||
//
|
||||
// @Summary Query All Items
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param q query string false "search string"
|
||||
// @Param page query int false "page number"
|
||||
// @Param pageSize query int false "items per page"
|
||||
// @Param labels query []string false "label Ids" collectionFormat(multi)
|
||||
// @Param locations query []string false "location Ids" collectionFormat(multi)
|
||||
// @Param parentIds query []string false "parent Ids" collectionFormat(multi)
|
||||
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
|
||||
// @Router /v1/items [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Query All Items
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param q query string false "search string"
|
||||
// @Param page query int false "page number"
|
||||
// @Param pageSize query int false "items per page"
|
||||
// @Param labels query []string false "label Ids" collectionFormat(multi)
|
||||
// @Param locations query []string false "location Ids" collectionFormat(multi)
|
||||
// @Param parentIds query []string false "parent Ids" collectionFormat(multi)
|
||||
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
|
||||
// @Router /v1/items [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemsGetAll() errchain.HandlerFunc {
|
||||
extractQuery := func(r *http.Request) repo.ItemQuery {
|
||||
params := r.URL.Query()
|
||||
@@ -108,13 +106,13 @@ func (ctrl *V1Controller) HandleItemsGetAll() errchain.HandlerFunc {
|
||||
|
||||
// HandleItemFullPath godoc
|
||||
//
|
||||
// @Summary Get the full path of an item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Success 200 {object} []repo.ItemPath
|
||||
// @Router /v1/items/{id}/path [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get the full path of an item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Success 200 {object} []repo.ItemPath
|
||||
// @Router /v1/items/{id}/path [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemFullPath() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) ([]repo.ItemPath, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -150,13 +148,13 @@ func (ctrl *V1Controller) HandleItemFullPath() errchain.HandlerFunc {
|
||||
|
||||
// HandleItemsCreate godoc
|
||||
//
|
||||
// @Summary Create Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param payload body repo.ItemCreate true "Item Data"
|
||||
// @Success 201 {object} repo.ItemSummary
|
||||
// @Router /v1/items [POST]
|
||||
// @Security Bearer
|
||||
// @Summary Create Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param payload body repo.ItemCreate true "Item Data"
|
||||
// @Success 201 {object} repo.ItemSummary
|
||||
// @Router /v1/items [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemsCreate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, body repo.ItemCreate) (repo.ItemOut, error) {
|
||||
return ctrl.svc.Items.Create(services.NewContext(r.Context()), body)
|
||||
@@ -167,13 +165,13 @@ func (ctrl *V1Controller) HandleItemsCreate() errchain.HandlerFunc {
|
||||
|
||||
// HandleItemGet godocs
|
||||
//
|
||||
// @Summary Get Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id} [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemGet() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (repo.ItemOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -186,13 +184,13 @@ func (ctrl *V1Controller) HandleItemGet() errchain.HandlerFunc {
|
||||
|
||||
// HandleItemDelete godocs
|
||||
//
|
||||
// @Summary Delete Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Success 204
|
||||
// @Router /v1/items/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
// @Summary Delete Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Success 204
|
||||
// @Router /v1/items/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemDelete() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -205,14 +203,14 @@ func (ctrl *V1Controller) HandleItemDelete() errchain.HandlerFunc {
|
||||
|
||||
// HandleItemUpdate godocs
|
||||
//
|
||||
// @Summary Update Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param payload body repo.ItemUpdate true "Item Data"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id} [PUT]
|
||||
// @Security Bearer
|
||||
// @Summary Update Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param payload body repo.ItemUpdate true "Item Data"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemUpdate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID, body repo.ItemUpdate) (repo.ItemOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -226,14 +224,14 @@ func (ctrl *V1Controller) HandleItemUpdate() errchain.HandlerFunc {
|
||||
|
||||
// HandleItemPatch godocs
|
||||
//
|
||||
// @Summary Update Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param payload body repo.ItemPatch true "Item Data"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id} [Patch]
|
||||
// @Security Bearer
|
||||
// @Summary Update Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param payload body repo.ItemPatch true "Item Data"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id} [Patch]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemPatch() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID, body repo.ItemPatch) (repo.ItemOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -252,13 +250,13 @@ func (ctrl *V1Controller) HandleItemPatch() errchain.HandlerFunc {
|
||||
|
||||
// HandleGetAllCustomFieldNames godocs
|
||||
//
|
||||
// @Summary Get All Custom Field Names
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Success 200
|
||||
// @Router /v1/items/fields [GET]
|
||||
// @Success 200 {object} []string
|
||||
// @Security Bearer
|
||||
// @Summary Get All Custom Field Names
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Success 200
|
||||
// @Router /v1/items/fields [GET]
|
||||
// @Success 200 {object} []string
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGetAllCustomFieldNames() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) ([]string, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -270,13 +268,13 @@ func (ctrl *V1Controller) HandleGetAllCustomFieldNames() errchain.HandlerFunc {
|
||||
|
||||
// HandleGetAllCustomFieldValues godocs
|
||||
//
|
||||
// @Summary Get All Custom Field Values
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Success 200
|
||||
// @Router /v1/items/fields/values [GET]
|
||||
// @Success 200 {object} []string
|
||||
// @Security Bearer
|
||||
// @Summary Get All Custom Field Values
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Success 200
|
||||
// @Router /v1/items/fields/values [GET]
|
||||
// @Success 200 {object} []string
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGetAllCustomFieldValues() errchain.HandlerFunc {
|
||||
type query struct {
|
||||
Field string `schema:"field" validate:"required"`
|
||||
@@ -294,7 +292,6 @@ func (ctrl *V1Controller) HandleGetAllCustomFieldValues() errchain.HandlerFunc {
|
||||
//
|
||||
// @Summary Import Items
|
||||
// @Tags Items
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Param csv formData file true "Image to upload"
|
||||
@@ -328,11 +325,11 @@ func (ctrl *V1Controller) HandleItemsImport() errchain.HandlerFunc {
|
||||
|
||||
// HandleItemsExport godocs
|
||||
//
|
||||
// @Summary Export Items
|
||||
// @Tags Items
|
||||
// @Success 200 {string} string "text/csv"
|
||||
// @Router /v1/items/export [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Export Items
|
||||
// @Tags Items
|
||||
// @Success 200 {string} string "text/csv"
|
||||
// @Router /v1/items/export [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemsExport() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
@@ -343,11 +340,8 @@ func (ctrl *V1Controller) HandleItemsExport() errchain.HandlerFunc {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
timestamp := time.Now().Format("2006-01-02_15-04-05") // YYYY-MM-DD_HH-MM-SS format
|
||||
filename := fmt.Sprintf("homebox-items_%s.csv", timestamp) // add timestamp to filename
|
||||
|
||||
w.Header().Set("Content-Type", "text/csv")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=%s", filename))
|
||||
w.Header().Set("Content-Disposition", "attachment;filename=homebox-items.csv")
|
||||
|
||||
writer := csv.NewWriter(w)
|
||||
writer.Comma = ','
|
||||
|
||||
@@ -25,7 +25,6 @@ type (
|
||||
//
|
||||
// @Summary Create Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param file formData file true "File attachment"
|
||||
@@ -105,41 +104,41 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc {
|
||||
|
||||
// HandleItemAttachmentGet godocs
|
||||
//
|
||||
// @Summary Get Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Produce application/octet-stream
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Success 200 {object} ItemAttachmentToken
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Produce application/octet-stream
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Success 200 {object} ItemAttachmentToken
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentGet() errchain.HandlerFunc {
|
||||
return ctrl.handleItemAttachmentsHandler
|
||||
}
|
||||
|
||||
// HandleItemAttachmentDelete godocs
|
||||
//
|
||||
// @Summary Delete Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Success 204
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE]
|
||||
// @Security Bearer
|
||||
// @Summary Delete Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Success 204
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentDelete() errchain.HandlerFunc {
|
||||
return ctrl.handleItemAttachmentsHandler
|
||||
}
|
||||
|
||||
// HandleItemAttachmentUpdate godocs
|
||||
//
|
||||
// @Summary Update Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Param payload body repo.ItemAttachmentUpdate true "Attachment Update"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [PUT]
|
||||
// @Security Bearer
|
||||
// @Summary Update Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Param payload body repo.ItemAttachmentUpdate true "Attachment Update"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentUpdate() errchain.HandlerFunc {
|
||||
return ctrl.handleItemAttachmentsHandler
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@ import (
|
||||
|
||||
// HandleLabelsGetAll godoc
|
||||
//
|
||||
// @Summary Get All Labels
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.LabelOut
|
||||
// @Router /v1/labels [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get All Labels
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.LabelOut
|
||||
// @Router /v1/labels [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelsGetAll() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) ([]repo.LabelSummary, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -29,13 +29,13 @@ func (ctrl *V1Controller) HandleLabelsGetAll() errchain.HandlerFunc {
|
||||
|
||||
// HandleLabelsCreate godoc
|
||||
//
|
||||
// @Summary Create Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param payload body repo.LabelCreate true "Label Data"
|
||||
// @Success 200 {object} repo.LabelSummary
|
||||
// @Router /v1/labels [POST]
|
||||
// @Security Bearer
|
||||
// @Summary Create Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param payload body repo.LabelCreate true "Label Data"
|
||||
// @Success 200 {object} repo.LabelSummary
|
||||
// @Router /v1/labels [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelsCreate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, data repo.LabelCreate) (repo.LabelOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -47,13 +47,13 @@ func (ctrl *V1Controller) HandleLabelsCreate() errchain.HandlerFunc {
|
||||
|
||||
// HandleLabelDelete godocs
|
||||
//
|
||||
// @Summary Delete Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 204
|
||||
// @Router /v1/labels/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
// @Summary Delete Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 204
|
||||
// @Router /v1/labels/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelDelete() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -66,13 +66,13 @@ func (ctrl *V1Controller) HandleLabelDelete() errchain.HandlerFunc {
|
||||
|
||||
// HandleLabelGet godocs
|
||||
//
|
||||
// @Summary Get Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 200 {object} repo.LabelOut
|
||||
// @Router /v1/labels/{id} [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 200 {object} repo.LabelOut
|
||||
// @Router /v1/labels/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelGet() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (repo.LabelOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -84,13 +84,13 @@ func (ctrl *V1Controller) HandleLabelGet() errchain.HandlerFunc {
|
||||
|
||||
// HandleLabelUpdate godocs
|
||||
//
|
||||
// @Summary Update Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 200 {object} repo.LabelOut
|
||||
// @Router /v1/labels/{id} [PUT]
|
||||
// @Security Bearer
|
||||
// @Summary Update Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 200 {object} repo.LabelOut
|
||||
// @Router /v1/labels/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelUpdate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID, data repo.LabelUpdate) (repo.LabelOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
|
||||
51
backend/app/api/handlers/v1/v1_ctrl_locales.go
Normal file
51
backend/app/api/handlers/v1/v1_ctrl_locales.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/httpkit/errchain"
|
||||
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
|
||||
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
|
||||
"github.com/sysadminsmedia/homebox/backend/internal/web/adapters"
|
||||
)
|
||||
|
||||
type Locales struct {
|
||||
Locales []string `json:"locales"`
|
||||
}
|
||||
|
||||
// HandleLocalesGetAll godoc
|
||||
//
|
||||
// @Summary Get All Locales
|
||||
// @Tags Locales
|
||||
// @Produce json
|
||||
// @Success 200 {object} []Locales
|
||||
// @Router /v1/locales [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocalesGetAll() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) ([]Locales, error) {
|
||||
// TODO: get a list of locales from files
|
||||
return []Locales{}, nil
|
||||
}
|
||||
|
||||
return adapters.Command(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleLocalesGet godoc
|
||||
//
|
||||
// @Summary Get Locale
|
||||
// @Tags Locales
|
||||
// @Produce json
|
||||
// @Param id path string true "Locale ID"
|
||||
// @Success 200 {object} interface{}
|
||||
// @Router /v1/locales/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocalesGet() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (interface{}, error) {
|
||||
// TODO: get the current locale
|
||||
return interface{}, nil
|
||||
}
|
||||
|
||||
return adapters.CommandID("id", fn, http.StatusOK)
|
||||
}
|
||||
@@ -14,13 +14,13 @@ import (
|
||||
|
||||
// HandleLocationTreeQuery godoc
|
||||
//
|
||||
// @Summary Get Locations Tree
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param withItems query bool false "include items in response tree"
|
||||
// @Success 200 {object} []repo.TreeItem
|
||||
// @Router /v1/locations/tree [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Locations Tree
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param withItems query bool false "include items in response tree"
|
||||
// @Success 200 {object} []repo.TreeItem
|
||||
// @Router /v1/locations/tree [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationTreeQuery() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, query repo.TreeQuery) ([]repo.TreeItem, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -32,13 +32,13 @@ func (ctrl *V1Controller) HandleLocationTreeQuery() errchain.HandlerFunc {
|
||||
|
||||
// HandleLocationGetAll godoc
|
||||
//
|
||||
// @Summary Get All Locations
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param filterChildren query bool false "Filter locations with parents"
|
||||
// @Success 200 {object} []repo.LocationOutCount
|
||||
// @Router /v1/locations [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get All Locations
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param filterChildren query bool false "Filter locations with parents"
|
||||
// @Success 200 {object} []repo.LocationOutCount
|
||||
// @Router /v1/locations [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationGetAll() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, q repo.LocationQuery) ([]repo.LocationOutCount, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -50,13 +50,13 @@ func (ctrl *V1Controller) HandleLocationGetAll() errchain.HandlerFunc {
|
||||
|
||||
// HandleLocationCreate godoc
|
||||
//
|
||||
// @Summary Create Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param payload body repo.LocationCreate true "Location Data"
|
||||
// @Success 200 {object} repo.LocationSummary
|
||||
// @Router /v1/locations [POST]
|
||||
// @Security Bearer
|
||||
// @Summary Create Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param payload body repo.LocationCreate true "Location Data"
|
||||
// @Success 200 {object} repo.LocationSummary
|
||||
// @Router /v1/locations [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationCreate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, createData repo.LocationCreate) (repo.LocationOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -68,13 +68,13 @@ func (ctrl *V1Controller) HandleLocationCreate() errchain.HandlerFunc {
|
||||
|
||||
// HandleLocationDelete godoc
|
||||
//
|
||||
// @Summary Delete Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Success 204
|
||||
// @Router /v1/locations/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
// @Summary Delete Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Success 204
|
||||
// @Router /v1/locations/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationDelete() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -124,13 +124,13 @@ func (ctrl *V1Controller) GetLocationWithPrice(auth context.Context, gid uuid.UU
|
||||
|
||||
// HandleLocationGet godoc
|
||||
//
|
||||
// @Summary Get Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Success 200 {object} repo.LocationOut
|
||||
// @Router /v1/locations/{id} [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Success 200 {object} repo.LocationOut
|
||||
// @Router /v1/locations/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationGet() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (repo.LocationOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -144,14 +144,14 @@ func (ctrl *V1Controller) HandleLocationGet() errchain.HandlerFunc {
|
||||
|
||||
// HandleLocationUpdate godoc
|
||||
//
|
||||
// @Summary Update Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Param payload body repo.LocationUpdate true "Location Data"
|
||||
// @Success 200 {object} repo.LocationOut
|
||||
// @Router /v1/locations/{id} [PUT]
|
||||
// @Security Bearer
|
||||
// @Summary Update Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Param payload body repo.LocationUpdate true "Location Data"
|
||||
// @Success 200 {object} repo.LocationOut
|
||||
// @Router /v1/locations/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationUpdate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID, body repo.LocationUpdate) (repo.LocationOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
// @Summary Get Maintenance Log
|
||||
// @Tags Item Maintenance
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param filters query repo.MaintenanceFilters false "which maintenance to retrieve"
|
||||
// @Success 200 {array} repo.MaintenanceEntryWithDetails[]
|
||||
// @Router /v1/items/{id}/maintenance [GET]
|
||||
@@ -34,7 +33,6 @@ func (ctrl *V1Controller) HandleMaintenanceLogGet() errchain.HandlerFunc {
|
||||
// @Summary Create Maintenance Entry
|
||||
// @Tags Item Maintenance
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param payload body repo.MaintenanceEntryCreate true "Entry Data"
|
||||
// @Success 201 {object} repo.MaintenanceEntry
|
||||
// @Router /v1/items/{id}/maintenance [POST]
|
||||
|
||||
@@ -12,13 +12,13 @@ import (
|
||||
|
||||
// HandleMaintenanceGetAll godoc
|
||||
//
|
||||
// @Summary Query All Maintenance
|
||||
// @Tags Maintenance
|
||||
// @Produce json
|
||||
// @Param filters query repo.MaintenanceFilters false "which maintenance to retrieve"
|
||||
// @Success 200 {array} repo.MaintenanceEntryWithDetails[]
|
||||
// @Router /v1/maintenance [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Query All Maintenance
|
||||
// @Tags Maintenance
|
||||
// @Produce json
|
||||
// @Param filters query repo.MaintenanceFilters false "which maintenance to retrieve"
|
||||
// @Success 200 {array} repo.MaintenanceEntryWithDetails[]
|
||||
// @Router /v1/maintenance [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleMaintenanceGetAll() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, filters repo.MaintenanceFilters) ([]repo.MaintenanceEntryWithDetails, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -33,7 +33,6 @@ func (ctrl *V1Controller) HandleMaintenanceGetAll() errchain.HandlerFunc {
|
||||
// @Summary Update Maintenance Entry
|
||||
// @Tags Maintenance
|
||||
// @Produce json
|
||||
// @Param id path string true "Maintenance ID"
|
||||
// @Param payload body repo.MaintenanceEntryUpdate true "Entry Data"
|
||||
// @Success 200 {object} repo.MaintenanceEntry
|
||||
// @Router /v1/maintenance/{id} [PUT]
|
||||
@@ -52,7 +51,6 @@ func (ctrl *V1Controller) HandleMaintenanceEntryUpdate() errchain.HandlerFunc {
|
||||
// @Summary Delete Maintenance Entry
|
||||
// @Tags Maintenance
|
||||
// @Produce json
|
||||
// @Param id path string true "Maintenance ID"
|
||||
// @Success 204
|
||||
// @Router /v1/maintenance/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
|
||||
@@ -13,12 +13,12 @@ import (
|
||||
|
||||
// HandleGetUserNotifiers godoc
|
||||
//
|
||||
// @Summary Get Notifiers
|
||||
// @Tags Notifiers
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.NotifierOut
|
||||
// @Router /v1/notifiers [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Notifiers
|
||||
// @Tags Notifiers
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.NotifierOut
|
||||
// @Router /v1/notifiers [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGetUserNotifiers() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, _ struct{}) ([]repo.NotifierOut, error) {
|
||||
user := services.UseUserCtx(r.Context())
|
||||
@@ -30,13 +30,13 @@ func (ctrl *V1Controller) HandleGetUserNotifiers() errchain.HandlerFunc {
|
||||
|
||||
// HandleCreateNotifier godoc
|
||||
//
|
||||
// @Summary Create Notifier
|
||||
// @Tags Notifiers
|
||||
// @Produce json
|
||||
// @Param payload body repo.NotifierCreate true "Notifier Data"
|
||||
// @Success 200 {object} repo.NotifierOut
|
||||
// @Router /v1/notifiers [POST]
|
||||
// @Security Bearer
|
||||
// @Summary Create Notifier
|
||||
// @Tags Notifiers
|
||||
// @Produce json
|
||||
// @Param payload body repo.NotifierCreate true "Notifier Data"
|
||||
// @Success 200 {object} repo.NotifierOut
|
||||
// @Router /v1/notifiers [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleCreateNotifier() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, in repo.NotifierCreate) (repo.NotifierOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -48,12 +48,12 @@ func (ctrl *V1Controller) HandleCreateNotifier() errchain.HandlerFunc {
|
||||
|
||||
// HandleDeleteNotifier godocs
|
||||
//
|
||||
// @Summary Delete a Notifier
|
||||
// @Tags Notifiers
|
||||
// @Param id path string true "Notifier ID"
|
||||
// @Success 204
|
||||
// @Router /v1/notifiers/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
// @Summary Delete a Notifier
|
||||
// @Tags Notifiers
|
||||
// @Param id path string true "Notifier ID"
|
||||
// @Success 204
|
||||
// @Router /v1/notifiers/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleDeleteNotifier() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -65,13 +65,13 @@ func (ctrl *V1Controller) HandleDeleteNotifier() errchain.HandlerFunc {
|
||||
|
||||
// HandleUpdateNotifier godocs
|
||||
//
|
||||
// @Summary Update Notifier
|
||||
// @Tags Notifiers
|
||||
// @Param id path string true "Notifier ID"
|
||||
// @Param payload body repo.NotifierUpdate true "Notifier Data"
|
||||
// @Success 200 {object} repo.NotifierOut
|
||||
// @Router /v1/notifiers/{id} [PUT]
|
||||
// @Security Bearer
|
||||
// @Summary Update Notifier
|
||||
// @Tags Notifiers
|
||||
// @Param id path string true "Notifier ID"
|
||||
// @Param payload body repo.NotifierUpdate true "Notifier Data"
|
||||
// @Success 200 {object} repo.NotifierOut
|
||||
// @Router /v1/notifiers/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUpdateNotifier() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID, in repo.NotifierUpdate) (repo.NotifierOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -86,6 +86,7 @@ func (ctrl *V1Controller) HandleUpdateNotifier() errchain.HandlerFunc {
|
||||
// @Summary Test Notifier
|
||||
// @Tags Notifiers
|
||||
// @Produce json
|
||||
// @Param id path string true "Notifier ID"
|
||||
// @Param url query string true "URL"
|
||||
// @Success 204
|
||||
// @Router /v1/notifiers/test [POST]
|
||||
|
||||
@@ -20,13 +20,13 @@ var qrcodeLogo []byte
|
||||
|
||||
// HandleGenerateQRCode godoc
|
||||
//
|
||||
// @Summary Create QR Code
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param data query string false "data to be encoded into qrcode"
|
||||
// @Success 200 {string} string "image/jpeg"
|
||||
// @Router /v1/qrcode [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Create QR Code
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param data query string false "data to be encoded into qrcode"
|
||||
// @Success 200 {string} string "image/jpeg"
|
||||
// @Router /v1/qrcode [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGenerateQRCode() errchain.HandlerFunc {
|
||||
type query struct {
|
||||
// 4,296 characters is the maximum length of a QR code
|
||||
|
||||
@@ -8,12 +8,12 @@ import (
|
||||
|
||||
// HandleBillOfMaterialsExport godoc
|
||||
//
|
||||
// @Summary Export Bill of Materials
|
||||
// @Tags Reporting
|
||||
// @Produce json
|
||||
// @Success 200 {string} string "text/csv"
|
||||
// @Router /v1/reporting/bill-of-materials [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Export Bill of Materials
|
||||
// @Tags Reporting
|
||||
// @Produce json
|
||||
// @Success 200 {string} string "text/csv"
|
||||
// @Router /v1/reporting/bill-of-materials [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleBillOfMaterialsExport() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
actor := services.UseUserCtx(r.Context())
|
||||
|
||||
@@ -14,12 +14,12 @@ import (
|
||||
|
||||
// HandleGroupStatisticsLocations godoc
|
||||
//
|
||||
// @Summary Get Location Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.TotalsByOrganizer
|
||||
// @Router /v1/groups/statistics/locations [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Location Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.TotalsByOrganizer
|
||||
// @Router /v1/groups/statistics/locations [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupStatisticsLocations() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) ([]repo.TotalsByOrganizer, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -31,12 +31,12 @@ func (ctrl *V1Controller) HandleGroupStatisticsLocations() errchain.HandlerFunc
|
||||
|
||||
// HandleGroupStatisticsLabels godoc
|
||||
//
|
||||
// @Summary Get Label Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.TotalsByOrganizer
|
||||
// @Router /v1/groups/statistics/labels [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Label Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.TotalsByOrganizer
|
||||
// @Router /v1/groups/statistics/labels [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupStatisticsLabels() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) ([]repo.TotalsByOrganizer, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -48,12 +48,12 @@ func (ctrl *V1Controller) HandleGroupStatisticsLabels() errchain.HandlerFunc {
|
||||
|
||||
// HandleGroupStatistics godoc
|
||||
//
|
||||
// @Summary Get Group Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.GroupStatistics
|
||||
// @Router /v1/groups/statistics [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Group Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.GroupStatistics
|
||||
// @Router /v1/groups/statistics [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupStatistics() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) (repo.GroupStatistics, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
@@ -65,14 +65,14 @@ func (ctrl *V1Controller) HandleGroupStatistics() errchain.HandlerFunc {
|
||||
|
||||
// HandleGroupStatisticsPriceOverTime godoc
|
||||
//
|
||||
// @Summary Get Purchase Price Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.ValueOverTime
|
||||
// @Param start query string false "start date"
|
||||
// @Param end query string false "end date"
|
||||
// @Router /v1/groups/statistics/purchase-price [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get Purchase Price Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.ValueOverTime
|
||||
// @Param start query string false "start date"
|
||||
// @Param end query string false "end date"
|
||||
// @Router /v1/groups/statistics/purchase-price [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupStatisticsPriceOverTime() errchain.HandlerFunc {
|
||||
parseDate := func(datestr string, defaultDate time.Time) (time.Time, error) {
|
||||
if datestr == "" {
|
||||
|
||||
@@ -15,12 +15,12 @@ import (
|
||||
|
||||
// HandleUserRegistration godoc
|
||||
//
|
||||
// @Summary Register New User
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Param payload body services.UserRegistration true "User Data"
|
||||
// @Success 204
|
||||
// @Router /v1/users/register [Post]
|
||||
// @Summary Register New User
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Param payload body services.UserRegistration true "User Data"
|
||||
// @Success 204
|
||||
// @Router /v1/users/register [Post]
|
||||
func (ctrl *V1Controller) HandleUserRegistration() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
regData := services.UserRegistration{}
|
||||
@@ -46,12 +46,12 @@ func (ctrl *V1Controller) HandleUserRegistration() errchain.HandlerFunc {
|
||||
|
||||
// HandleUserSelf godoc
|
||||
//
|
||||
// @Summary Get User Self
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Success 200 {object} Wrapped{item=repo.UserOut}
|
||||
// @Router /v1/users/self [GET]
|
||||
// @Security Bearer
|
||||
// @Summary Get User Self
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Success 200 {object} Wrapped{item=repo.UserOut}
|
||||
// @Router /v1/users/self [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelf() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
token := services.UseTokenCtx(r.Context())
|
||||
@@ -67,13 +67,13 @@ func (ctrl *V1Controller) HandleUserSelf() errchain.HandlerFunc {
|
||||
|
||||
// HandleUserSelfUpdate godoc
|
||||
//
|
||||
// @Summary Update Account
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Param payload body repo.UserUpdate true "User Data"
|
||||
// @Success 200 {object} Wrapped{item=repo.UserUpdate}
|
||||
// @Router /v1/users/self [PUT]
|
||||
// @Security Bearer
|
||||
// @Summary Update Account
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Param payload body repo.UserUpdate true "User Data"
|
||||
// @Success 200 {object} Wrapped{item=repo.UserUpdate}
|
||||
// @Router /v1/users/self [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelfUpdate() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
updateData := repo.UserUpdate{}
|
||||
@@ -94,12 +94,12 @@ func (ctrl *V1Controller) HandleUserSelfUpdate() errchain.HandlerFunc {
|
||||
|
||||
// HandleUserSelfDelete godoc
|
||||
//
|
||||
// @Summary Delete Account
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Router /v1/users/self [DELETE]
|
||||
// @Security Bearer
|
||||
// @Summary Delete Account
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Router /v1/users/self [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelfDelete() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
if ctrl.isDemo {
|
||||
@@ -124,12 +124,12 @@ type (
|
||||
|
||||
// HandleUserSelfChangePassword godoc
|
||||
//
|
||||
// @Summary Change Password
|
||||
// @Tags User
|
||||
// @Success 204
|
||||
// @Param payload body ChangePassword true "Password Payload"
|
||||
// @Router /v1/users/change-password [PUT]
|
||||
// @Security Bearer
|
||||
// @Summary Change Password
|
||||
// @Tags User
|
||||
// @Success 204
|
||||
// @Param payload body ChangePassword true "Password Payload"
|
||||
// @Router /v1/users/change-password [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelfChangePassword() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
if ctrl.isDemo {
|
||||
|
||||
@@ -46,15 +46,15 @@ func build() string {
|
||||
return fmt.Sprintf("%s, commit %s, built at %s", version, short, buildTime)
|
||||
}
|
||||
|
||||
// @title Homebox API
|
||||
// @version 1.0
|
||||
// @description Track, Manage, and Organize your Things.
|
||||
// @contact.name Don't
|
||||
// @BasePath /api
|
||||
// @securityDefinitions.apikey Bearer
|
||||
// @in header
|
||||
// @name Authorization
|
||||
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
|
||||
// @title Homebox API
|
||||
// @version 1.0
|
||||
// @description Track, Manage, and Organize your Things.
|
||||
// @contact.name Don't
|
||||
// @BasePath /api
|
||||
// @securityDefinitions.apikey Bearer
|
||||
// @in header
|
||||
// @name Authorization
|
||||
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
|
||||
func main() {
|
||||
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
|
||||
|
||||
@@ -254,14 +254,15 @@ func run(cfg *config.Config) error {
|
||||
}
|
||||
}))
|
||||
|
||||
if cfg.Options.GithubReleaseCheck {
|
||||
runner.AddPlugin(NewTask("get-latest-github-release", time.Hour, func(ctx context.Context) {
|
||||
log.Debug().Msg("running get latest github release")
|
||||
err := app.services.BackgroundService.GetLatestGithubRelease(context.Background())
|
||||
// TODO: read from env var0 GOOS=linux go build
|
||||
if true {
|
||||
runner.AddPlugin(NewTask("locale-update", time.Duration(24)*time.Hour, func(ctx context.Context) {
|
||||
log.Debug().Msg("running locale update")
|
||||
err := app.services.BackgroundService.UpdateLocales(ctx)
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Err(err).
|
||||
Msg("failed to get latest github release")
|
||||
Msg("failed to update locales")
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -566,9 +566,6 @@ const docTemplate = `{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"multipart/form-data"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -740,9 +737,6 @@ const docTemplate = `{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"multipart/form-data"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -927,13 +921,6 @@ const docTemplate = `{
|
||||
],
|
||||
"summary": "Get Maintenance Log",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Item ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"scheduled",
|
||||
@@ -976,13 +963,6 @@ const docTemplate = `{
|
||||
],
|
||||
"summary": "Create Maintenance Entry",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Item ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Entry Data",
|
||||
"name": "payload",
|
||||
@@ -1454,13 +1434,6 @@ const docTemplate = `{
|
||||
],
|
||||
"summary": "Update Maintenance Entry",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Maintenance ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Entry Data",
|
||||
"name": "payload",
|
||||
@@ -1493,15 +1466,6 @@ const docTemplate = `{
|
||||
"Maintenance"
|
||||
],
|
||||
"summary": "Delete Maintenance Entry",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Maintenance ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
@@ -1584,6 +1548,13 @@ const docTemplate = `{
|
||||
],
|
||||
"summary": "Test Notifier",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Notifier ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "URL",
|
||||
@@ -1781,6 +1752,20 @@ const docTemplate = `{
|
||||
],
|
||||
"summary": "User Login",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"example": "admin@admin.com",
|
||||
"description": "string",
|
||||
"name": "username",
|
||||
"in": "formData"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"example": "admin",
|
||||
"description": "string",
|
||||
"name": "password",
|
||||
"in": "formData"
|
||||
},
|
||||
{
|
||||
"description": "Login Data",
|
||||
"name": "payload",
|
||||
@@ -2257,9 +2242,6 @@ const docTemplate = `{
|
||||
"soldTo": {
|
||||
"type": "string"
|
||||
},
|
||||
"syncChildItemsLocations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2304,10 +2286,6 @@ const docTemplate = `{
|
||||
"archived": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"assetId": {
|
||||
"type": "string",
|
||||
"example": "0"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2462,9 +2440,6 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"maxLength": 255
|
||||
},
|
||||
"syncChildItemsLocations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"warrantyDetails": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2950,17 +2925,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"services.Latest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"date": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"services.UserRegistration": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2993,9 +2957,6 @@ const docTemplate = `{
|
||||
"health": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"latest": {
|
||||
"$ref": "#/definitions/services.Latest"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3085,15 +3046,13 @@ const docTemplate = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string",
|
||||
"example": "admin"
|
||||
"type": "string"
|
||||
},
|
||||
"stayLoggedIn": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"example": "admin@admin.com"
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -559,9 +559,6 @@
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"multipart/form-data"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -733,9 +730,6 @@
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"multipart/form-data"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -920,13 +914,6 @@
|
||||
],
|
||||
"summary": "Get Maintenance Log",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Item ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"scheduled",
|
||||
@@ -969,13 +956,6 @@
|
||||
],
|
||||
"summary": "Create Maintenance Entry",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Item ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Entry Data",
|
||||
"name": "payload",
|
||||
@@ -1447,13 +1427,6 @@
|
||||
],
|
||||
"summary": "Update Maintenance Entry",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Maintenance ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Entry Data",
|
||||
"name": "payload",
|
||||
@@ -1486,15 +1459,6 @@
|
||||
"Maintenance"
|
||||
],
|
||||
"summary": "Delete Maintenance Entry",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Maintenance ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
@@ -1577,6 +1541,13 @@
|
||||
],
|
||||
"summary": "Test Notifier",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Notifier ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "URL",
|
||||
@@ -1774,6 +1745,20 @@
|
||||
],
|
||||
"summary": "User Login",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"example": "admin@admin.com",
|
||||
"description": "string",
|
||||
"name": "username",
|
||||
"in": "formData"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"example": "admin",
|
||||
"description": "string",
|
||||
"name": "password",
|
||||
"in": "formData"
|
||||
},
|
||||
{
|
||||
"description": "Login Data",
|
||||
"name": "payload",
|
||||
@@ -2250,9 +2235,6 @@
|
||||
"soldTo": {
|
||||
"type": "string"
|
||||
},
|
||||
"syncChildItemsLocations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2297,10 +2279,6 @@
|
||||
"archived": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"assetId": {
|
||||
"type": "string",
|
||||
"example": "0"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2455,9 +2433,6 @@
|
||||
"type": "string",
|
||||
"maxLength": 255
|
||||
},
|
||||
"syncChildItemsLocations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"warrantyDetails": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2943,17 +2918,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"services.Latest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"date": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"services.UserRegistration": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2986,9 +2950,6 @@
|
||||
"health": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"latest": {
|
||||
"$ref": "#/definitions/services.Latest"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3078,15 +3039,13 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string",
|
||||
"example": "admin"
|
||||
"type": "string"
|
||||
},
|
||||
"stayLoggedIn": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"example": "admin@admin.com"
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -188,8 +188,6 @@ definitions:
|
||||
type: string
|
||||
soldTo:
|
||||
type: string
|
||||
syncChildItemsLocations:
|
||||
type: boolean
|
||||
updatedAt:
|
||||
type: string
|
||||
warrantyDetails:
|
||||
@@ -219,9 +217,6 @@ definitions:
|
||||
properties:
|
||||
archived:
|
||||
type: boolean
|
||||
assetId:
|
||||
example: "0"
|
||||
type: string
|
||||
createdAt:
|
||||
type: string
|
||||
description:
|
||||
@@ -328,8 +323,6 @@ definitions:
|
||||
soldTo:
|
||||
maxLength: 255
|
||||
type: string
|
||||
syncChildItemsLocations:
|
||||
type: boolean
|
||||
warrantyDetails:
|
||||
type: string
|
||||
warrantyExpires:
|
||||
@@ -654,13 +647,6 @@ definitions:
|
||||
value:
|
||||
type: number
|
||||
type: object
|
||||
services.Latest:
|
||||
properties:
|
||||
date:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
services.UserRegistration:
|
||||
properties:
|
||||
email:
|
||||
@@ -682,8 +668,6 @@ definitions:
|
||||
type: boolean
|
||||
health:
|
||||
type: boolean
|
||||
latest:
|
||||
$ref: '#/definitions/services.Latest'
|
||||
message:
|
||||
type: string
|
||||
title:
|
||||
@@ -742,12 +726,10 @@ definitions:
|
||||
v1.LoginForm:
|
||||
properties:
|
||||
password:
|
||||
example: admin
|
||||
type: string
|
||||
stayLoggedIn:
|
||||
type: boolean
|
||||
username:
|
||||
example: admin@admin.com
|
||||
type: string
|
||||
type: object
|
||||
v1.TokenResponse:
|
||||
@@ -1150,8 +1132,6 @@ paths:
|
||||
- Items
|
||||
/v1/items/{id}/attachments:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
parameters:
|
||||
- description: Item ID
|
||||
in: path
|
||||
@@ -1265,11 +1245,6 @@ paths:
|
||||
/v1/items/{id}/maintenance:
|
||||
get:
|
||||
parameters:
|
||||
- description: Item ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- enum:
|
||||
- scheduled
|
||||
- completed
|
||||
@@ -1297,11 +1272,6 @@ paths:
|
||||
- Item Maintenance
|
||||
post:
|
||||
parameters:
|
||||
- description: Item ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: Entry Data
|
||||
in: body
|
||||
name: payload
|
||||
@@ -1388,8 +1358,6 @@ paths:
|
||||
- Items
|
||||
/v1/items/import:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
parameters:
|
||||
- description: Image to upload
|
||||
in: formData
|
||||
@@ -1652,12 +1620,6 @@ paths:
|
||||
- Maintenance
|
||||
/v1/maintenance/{id}:
|
||||
delete:
|
||||
parameters:
|
||||
- description: Maintenance ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -1670,11 +1632,6 @@ paths:
|
||||
- Maintenance
|
||||
put:
|
||||
parameters:
|
||||
- description: Maintenance ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: Entry Data
|
||||
in: body
|
||||
name: payload
|
||||
@@ -1771,6 +1728,11 @@ paths:
|
||||
/v1/notifiers/test:
|
||||
post:
|
||||
parameters:
|
||||
- description: Notifier ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: URL
|
||||
in: query
|
||||
name: url
|
||||
@@ -1854,6 +1816,16 @@ paths:
|
||||
- application/x-www-form-urlencoded
|
||||
- application/json
|
||||
parameters:
|
||||
- description: string
|
||||
example: admin@admin.com
|
||||
in: formData
|
||||
name: username
|
||||
type: string
|
||||
- description: string
|
||||
example: admin
|
||||
in: formData
|
||||
name: password
|
||||
type: string
|
||||
- description: Login Data
|
||||
in: body
|
||||
name: payload
|
||||
|
||||
@@ -36,7 +36,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Generate migrations using Atlas support for MySQL (note the Ent dialect option passed above).
|
||||
err = migrate.NamedDiff(ctx, "sqlite://.data/homebox.migration.db?_fk=1&_time_format=sqlite", os.Args[1], opts...)
|
||||
err = migrate.NamedDiff(ctx, "sqlite://.data/homebox.migration.db?_fk=1", os.Args[1], opts...)
|
||||
if err != nil {
|
||||
log.Fatalf("failed generating migration file: %v", err)
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ module github.com/sysadminsmedia/homebox/backend
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
ariga.io/atlas v0.29.1
|
||||
ariga.io/atlas v0.19.1
|
||||
entgo.io/ent v0.14.1
|
||||
github.com/ardanlabs/conf/v3 v3.2.0
|
||||
github.com/ardanlabs/conf/v3 v3.1.8
|
||||
github.com/containrrr/shoutrrr v0.8.0
|
||||
github.com/go-chi/chi/v5 v5.2.0
|
||||
github.com/go-playground/validator/v10 v10.23.0
|
||||
github.com/go-chi/chi/v5 v5.1.0
|
||||
github.com/go-playground/validator/v10 v10.22.1
|
||||
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/schema v1.4.1
|
||||
@@ -17,40 +17,39 @@ require (
|
||||
github.com/olahol/melody v1.2.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/swaggo/http-swagger/v2 v2.0.2
|
||||
github.com/swaggo/swag v1.16.4
|
||||
github.com/swaggo/swag v1.16.3
|
||||
github.com/yeqown/go-qrcode/v2 v2.2.4
|
||||
github.com/yeqown/go-qrcode/writer/standard v1.2.4
|
||||
golang.org/x/crypto v0.31.0
|
||||
modernc.org/sqlite v1.34.4
|
||||
golang.org/x/crypto v0.28.0
|
||||
modernc.org/sqlite v1.33.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/bmatcuk/doublestar v1.3.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/fogleman/gg v1.3.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/go-openapi/inflect v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/spec v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/spec v0.20.9 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.23.0 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.19.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
@@ -58,22 +57,20 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/swaggo/files/v2 v2.0.2 // indirect
|
||||
github.com/swaggo/files/v2 v2.0.0 // indirect
|
||||
github.com/yeqown/reedsolomon v1.0.0 // indirect
|
||||
github.com/zclconf/go-cty v1.16.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 // indirect
|
||||
golang.org/x/image v0.23.0 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
github.com/zclconf/go-cty v1.14.1 // indirect
|
||||
golang.org/x/image v0.18.0 // indirect
|
||||
golang.org/x/mod v0.20.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20241223112719-96e2e1e4408d // indirect
|
||||
modernc.org/libc v1.61.6 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.1 // indirect
|
||||
modernc.org/strutil v1.2.1 // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
|
||||
modernc.org/libc v1.55.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/strutil v1.2.0 // indirect
|
||||
modernc.org/token v1.1.0 // indirect
|
||||
)
|
||||
|
||||
114
backend/go.sum
114
backend/go.sum
@@ -1,7 +1,9 @@
|
||||
ariga.io/atlas v0.19.1 h1:QzBHkakwzEhmPWOzNhw8Yr/Bbicj6Iq5hwEoNI/Jr9A=
|
||||
ariga.io/atlas v0.19.1/go.mod h1:VPlcXdd4w2KqKnH54yEZcry79UAhpaWaxEsmn5JRNoE=
|
||||
ariga.io/atlas v0.29.1 h1:7gB8XRFTnJeZ7ZiccNCJqwBtUv3yjFyxRFDMzu0AmRg=
|
||||
ariga.io/atlas v0.29.1/go.mod h1:lkLAw/t2/P7g5CFYlYmHvNuShlmGujwm3OGsW00xowI=
|
||||
ariga.io/atlas v0.28.0 h1:qmn9tUyJypJkIw+X3ECUwDtkMTiFupgstHbjRN4xGH0=
|
||||
ariga.io/atlas v0.28.0/go.mod h1:LOOp18LCL9r+VifvVlJqgYJwYl271rrXD9/wIyzJ8sw=
|
||||
entgo.io/ent v0.12.5 h1:KREM5E4CSoej4zeGa88Ou/gfturAnpUv0mzAjch1sj4=
|
||||
entgo.io/ent v0.12.5/go.mod h1:Y3JVAjtlIk8xVZYSn3t3mf8xlZIn5SAOXZQxD6kKI+Q=
|
||||
entgo.io/ent v0.14.1 h1:fUERL506Pqr92EPHJqr8EYxbPioflJo6PudkrEA8a/s=
|
||||
entgo.io/ent v0.14.1/go.mod h1:MH6XLG0KXpkcDQhKiHfANZSzR55TJyPL5IGNpI8wpco=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
@@ -14,10 +16,6 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
|
||||
github.com/ardanlabs/conf/v3 v3.1.8 h1:r0KUV9/Hni5XdeWR2+A1BiedIDnry5CjezoqgJ0rnFQ=
|
||||
github.com/ardanlabs/conf/v3 v3.1.8/go.mod h1:OIi6NK95fj8jKFPdZ/UmcPlY37JBg99hdP9o5XmNK9c=
|
||||
github.com/ardanlabs/conf/v3 v3.2.0 h1:Xi7OwSBupZLUYIFBGBRl6pHUXiw/hp+xP90h+UZby0c=
|
||||
github.com/ardanlabs/conf/v3 v3.2.0/go.mod h1:OIi6NK95fj8jKFPdZ/UmcPlY37JBg99hdP9o5XmNK9c=
|
||||
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
|
||||
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
|
||||
github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec=
|
||||
github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
@@ -29,57 +27,41 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
|
||||
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
|
||||
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
|
||||
github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk=
|
||||
github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
|
||||
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8=
|
||||
github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
|
||||
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
||||
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
|
||||
github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
|
||||
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
@@ -101,16 +83,10 @@ github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E=
|
||||
github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI=
|
||||
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
|
||||
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
|
||||
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
|
||||
github.com/hay-kot/httpkit v0.0.11 h1:ZdB2uqsFBSDpfUoClGK5c5orjBjQkEVSXh7fZX5FKEk=
|
||||
github.com/hay-kot/httpkit v0.0.11/go.mod h1:0kZdk5/swzdfqfg2c6pBWimcgeJ9PTyO97EbHnYl2Sw=
|
||||
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
|
||||
@@ -134,8 +110,6 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
@@ -144,6 +118,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0=
|
||||
github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
|
||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||
@@ -186,18 +162,12 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw=
|
||||
github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
|
||||
github.com/swaggo/files/v2 v2.0.2 h1:Bq4tgS/yxLB/3nwOMcul5oLEUKa877Ykgz3CJMVbQKU=
|
||||
github.com/swaggo/files/v2 v2.0.2/go.mod h1:TVqetIzZsO9OhHX1Am9sRf9LdrFZqoK49N37KON/jr0=
|
||||
github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSyIKC9OBg=
|
||||
github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ=
|
||||
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
||||
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||
github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
|
||||
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
|
||||
github.com/yeqown/go-qrcode/v2 v2.2.4 h1:cXdYlrhzHzVAnJHiwr/T6lAUmS9MtEStjEZBjArrvnc=
|
||||
github.com/yeqown/go-qrcode/v2 v2.2.4/go.mod h1:uHpt9CM0V1HeXLz+Wg5MN50/sI/fQhfkZlOM+cOTHxw=
|
||||
github.com/yeqown/go-qrcode/writer/standard v1.2.4 h1:41e/aLr1AMVWlug6oUMkDg2r0+dv5ofB7UaTkekKZBc=
|
||||
@@ -206,39 +176,39 @@ github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr
|
||||
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
|
||||
github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA=
|
||||
github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
github.com/zclconf/go-cty v1.16.0 h1:xPKEhst+BW5D0wxebMZkxgapvOE/dw7bFTlgSc9nD6w=
|
||||
github.com/zclconf/go-cty v1.16.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 h1:9kj3STMvgqy3YA4VQXBrN7925ICMxD5wzMRcgA30588=
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
|
||||
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
|
||||
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
|
||||
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -253,41 +223,21 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
|
||||
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
|
||||
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
|
||||
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
|
||||
modernc.org/gc/v3 v3.0.0-20241223112719-96e2e1e4408d h1:d0JExN5U5FjUVHCP6L9DIlLJBZveR6KUM4AvfDUL3+k=
|
||||
modernc.org/gc/v3 v3.0.0-20241223112719-96e2e1e4408d/go.mod h1:qBSLm/exCqouT2hrfyTKikWKG9IPq8EoX5fS00l3jqk=
|
||||
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
|
||||
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
|
||||
modernc.org/libc v1.61.6 h1:L2jW0wxHPCyHK0YSHaGaVlY0WxjpG/TTVdg6gRJOPqw=
|
||||
modernc.org/libc v1.61.6/go.mod h1:G+DzuaCcReUYYg4nNSfigIfTDCENdj9EByglvaRx53A=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||
modernc.org/memory v1.8.1 h1:HS1HRg1jEohnuONobEq2WrLEhLyw8+J42yLFTnllm2A=
|
||||
modernc.org/memory v1.8.1/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
|
||||
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
|
||||
modernc.org/sqlite v1.33.0 h1:WWkA/T2G17okiLGgKAj4/RMIvgyMT19yQ038160IeYk=
|
||||
modernc.org/sqlite v1.33.0/go.mod h1:9uQ9hF/pCZoYZK73D/ud5Z7cIRIILSZI8NdIemVMTX8=
|
||||
modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM=
|
||||
modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
|
||||
modernc.org/sqlite v1.34.4 h1:sjdARozcL5KJBvYQvLlZEmctRgW9xqIZc2ncN7PU0P8=
|
||||
modernc.org/sqlite v1.34.4/go.mod h1:3QQFCG2SEMtc2nv+Wq4cQCH7Hjcg+p/RMlS1XK+zwbk=
|
||||
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -61,7 +61,7 @@ func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices {
|
||||
repo: repos,
|
||||
autoIncrementAssetID: options.autoIncrementAssetID,
|
||||
},
|
||||
BackgroundService: &BackgroundService{repos, Latest{}},
|
||||
BackgroundService: &BackgroundService{repos},
|
||||
Currencies: currencies.NewCurrencyService(options.currencies),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func bootstrap() {
|
||||
}
|
||||
|
||||
func MainNoExit(m *testing.M) int {
|
||||
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1&_time_format=sqlite")
|
||||
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
|
||||
if err != nil {
|
||||
log.Fatalf("failed opening connection to sqlite: %v", err)
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -14,13 +11,8 @@ import (
|
||||
"github.com/sysadminsmedia/homebox/backend/internal/data/types"
|
||||
)
|
||||
|
||||
type Latest struct {
|
||||
Version string `json:"version"`
|
||||
Date string `json:"date"`
|
||||
}
|
||||
type BackgroundService struct {
|
||||
repos *repo.AllRepos
|
||||
latest Latest
|
||||
}
|
||||
|
||||
func (svc *BackgroundService) SendNotifiersToday(ctx context.Context) error {
|
||||
@@ -88,51 +80,19 @@ func (svc *BackgroundService) SendNotifiersToday(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc *BackgroundService) GetLatestGithubRelease(ctx context.Context) error {
|
||||
url := "https://api.github.com/repos/sysadminsmedia/homebox/releases/latest"
|
||||
func (svc *BackgroundService) UpdateLocales(ctx context.Context) error {
|
||||
log.Debug().Msg("updating locales")
|
||||
// fetch list of locales from github
|
||||
// is it worth checking if any changes have been made?
|
||||
// download locales overwriting files in static/public/locales
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create latest version request: %w", err)
|
||||
}
|
||||
// curl -H "Accept: application/vnd.github.v3+json" \
|
||||
// -H "If-Modified-Since: Thu, 31 Oct 2024 09:59:02 GMT" \
|
||||
// -o /dev/null -s -w "%{http_code}\n" \
|
||||
// https://api.github.com/repos/sysadminsmedia/homebox/contents/frontend/locales
|
||||
// keep track of last modified date
|
||||
|
||||
req.Header.Set("User-Agent", "Homebox-Version-Checker")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to make latest version request: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
err := resp.Body.Close()
|
||||
if err != nil {
|
||||
log.Printf("error closing latest version response body: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("latest version unexpected status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// ignoring fields that are not relevant
|
||||
type Release struct {
|
||||
ReleaseVersion string `json:"tag_name"`
|
||||
PublishedAt time.Time `json:"published_at"`
|
||||
}
|
||||
|
||||
var release Release
|
||||
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
|
||||
return fmt.Errorf("failed to decode latest version response: %w", err)
|
||||
}
|
||||
|
||||
svc.latest = Latest{
|
||||
Version: release.ReleaseVersion,
|
||||
Date: release.PublishedAt.String(),
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc *BackgroundService) GetLatestVersion() (Latest) {
|
||||
return svc.latest
|
||||
}
|
||||
@@ -40,8 +40,6 @@ type Item struct {
|
||||
Archived bool `json:"archived,omitempty"`
|
||||
// AssetID holds the value of the "asset_id" field.
|
||||
AssetID int `json:"asset_id,omitempty"`
|
||||
// SyncChildItemsLocations holds the value of the "sync_child_items_locations" field.
|
||||
SyncChildItemsLocations bool `json:"sync_child_items_locations,omitempty"`
|
||||
// SerialNumber holds the value of the "serial_number" field.
|
||||
SerialNumber string `json:"serial_number,omitempty"`
|
||||
// ModelNumber holds the value of the "model_number" field.
|
||||
@@ -183,7 +181,7 @@ func (*Item) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case item.FieldInsured, item.FieldArchived, item.FieldSyncChildItemsLocations, item.FieldLifetimeWarranty:
|
||||
case item.FieldInsured, item.FieldArchived, item.FieldLifetimeWarranty:
|
||||
values[i] = new(sql.NullBool)
|
||||
case item.FieldPurchasePrice, item.FieldSoldPrice:
|
||||
values[i] = new(sql.NullFloat64)
|
||||
@@ -282,12 +280,6 @@ func (i *Item) assignValues(columns []string, values []any) error {
|
||||
} else if value.Valid {
|
||||
i.AssetID = int(value.Int64)
|
||||
}
|
||||
case item.FieldSyncChildItemsLocations:
|
||||
if value, ok := values[j].(*sql.NullBool); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field sync_child_items_locations", values[j])
|
||||
} else if value.Valid {
|
||||
i.SyncChildItemsLocations = value.Bool
|
||||
}
|
||||
case item.FieldSerialNumber:
|
||||
if value, ok := values[j].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field serial_number", values[j])
|
||||
@@ -493,9 +485,6 @@ func (i *Item) String() string {
|
||||
builder.WriteString("asset_id=")
|
||||
builder.WriteString(fmt.Sprintf("%v", i.AssetID))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("sync_child_items_locations=")
|
||||
builder.WriteString(fmt.Sprintf("%v", i.SyncChildItemsLocations))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("serial_number=")
|
||||
builder.WriteString(i.SerialNumber)
|
||||
builder.WriteString(", ")
|
||||
|
||||
@@ -35,8 +35,6 @@ const (
|
||||
FieldArchived = "archived"
|
||||
// FieldAssetID holds the string denoting the asset_id field in the database.
|
||||
FieldAssetID = "asset_id"
|
||||
// FieldSyncChildItemsLocations holds the string denoting the sync_child_items_locations field in the database.
|
||||
FieldSyncChildItemsLocations = "sync_child_items_locations"
|
||||
// FieldSerialNumber holds the string denoting the serial_number field in the database.
|
||||
FieldSerialNumber = "serial_number"
|
||||
// FieldModelNumber holds the string denoting the model_number field in the database.
|
||||
@@ -144,7 +142,6 @@ var Columns = []string{
|
||||
FieldInsured,
|
||||
FieldArchived,
|
||||
FieldAssetID,
|
||||
FieldSyncChildItemsLocations,
|
||||
FieldSerialNumber,
|
||||
FieldModelNumber,
|
||||
FieldManufacturer,
|
||||
@@ -212,8 +209,6 @@ var (
|
||||
DefaultArchived bool
|
||||
// DefaultAssetID holds the default value on creation for the "asset_id" field.
|
||||
DefaultAssetID int
|
||||
// DefaultSyncChildItemsLocations holds the default value on creation for the "sync_child_items_locations" field.
|
||||
DefaultSyncChildItemsLocations bool
|
||||
// SerialNumberValidator is a validator for the "serial_number" field. It is called by the builders before save.
|
||||
SerialNumberValidator func(string) error
|
||||
// ModelNumberValidator is a validator for the "model_number" field. It is called by the builders before save.
|
||||
@@ -292,11 +287,6 @@ func ByAssetID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldAssetID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySyncChildItemsLocations orders the results by the sync_child_items_locations field.
|
||||
func BySyncChildItemsLocations(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSyncChildItemsLocations, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySerialNumber orders the results by the serial_number field.
|
||||
func BySerialNumber(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSerialNumber, opts...).ToFunc()
|
||||
|
||||
@@ -106,11 +106,6 @@ func AssetID(v int) predicate.Item {
|
||||
return predicate.Item(sql.FieldEQ(FieldAssetID, v))
|
||||
}
|
||||
|
||||
// SyncChildItemsLocations applies equality check predicate on the "sync_child_items_locations" field. It's identical to SyncChildItemsLocationsEQ.
|
||||
func SyncChildItemsLocations(v bool) predicate.Item {
|
||||
return predicate.Item(sql.FieldEQ(FieldSyncChildItemsLocations, v))
|
||||
}
|
||||
|
||||
// SerialNumber applies equality check predicate on the "serial_number" field. It's identical to SerialNumberEQ.
|
||||
func SerialNumber(v string) predicate.Item {
|
||||
return predicate.Item(sql.FieldEQ(FieldSerialNumber, v))
|
||||
@@ -646,16 +641,6 @@ func AssetIDLTE(v int) predicate.Item {
|
||||
return predicate.Item(sql.FieldLTE(FieldAssetID, v))
|
||||
}
|
||||
|
||||
// SyncChildItemsLocationsEQ applies the EQ predicate on the "sync_child_items_locations" field.
|
||||
func SyncChildItemsLocationsEQ(v bool) predicate.Item {
|
||||
return predicate.Item(sql.FieldEQ(FieldSyncChildItemsLocations, v))
|
||||
}
|
||||
|
||||
// SyncChildItemsLocationsNEQ applies the NEQ predicate on the "sync_child_items_locations" field.
|
||||
func SyncChildItemsLocationsNEQ(v bool) predicate.Item {
|
||||
return predicate.Item(sql.FieldNEQ(FieldSyncChildItemsLocations, v))
|
||||
}
|
||||
|
||||
// SerialNumberEQ applies the EQ predicate on the "serial_number" field.
|
||||
func SerialNumberEQ(v string) predicate.Item {
|
||||
return predicate.Item(sql.FieldEQ(FieldSerialNumber, v))
|
||||
|
||||
@@ -159,20 +159,6 @@ func (ic *ItemCreate) SetNillableAssetID(i *int) *ItemCreate {
|
||||
return ic
|
||||
}
|
||||
|
||||
// SetSyncChildItemsLocations sets the "sync_child_items_locations" field.
|
||||
func (ic *ItemCreate) SetSyncChildItemsLocations(b bool) *ItemCreate {
|
||||
ic.mutation.SetSyncChildItemsLocations(b)
|
||||
return ic
|
||||
}
|
||||
|
||||
// SetNillableSyncChildItemsLocations sets the "sync_child_items_locations" field if the given value is not nil.
|
||||
func (ic *ItemCreate) SetNillableSyncChildItemsLocations(b *bool) *ItemCreate {
|
||||
if b != nil {
|
||||
ic.SetSyncChildItemsLocations(*b)
|
||||
}
|
||||
return ic
|
||||
}
|
||||
|
||||
// SetSerialNumber sets the "serial_number" field.
|
||||
func (ic *ItemCreate) SetSerialNumber(s string) *ItemCreate {
|
||||
ic.mutation.SetSerialNumber(s)
|
||||
@@ -552,10 +538,6 @@ func (ic *ItemCreate) defaults() {
|
||||
v := item.DefaultAssetID
|
||||
ic.mutation.SetAssetID(v)
|
||||
}
|
||||
if _, ok := ic.mutation.SyncChildItemsLocations(); !ok {
|
||||
v := item.DefaultSyncChildItemsLocations
|
||||
ic.mutation.SetSyncChildItemsLocations(v)
|
||||
}
|
||||
if _, ok := ic.mutation.LifetimeWarranty(); !ok {
|
||||
v := item.DefaultLifetimeWarranty
|
||||
ic.mutation.SetLifetimeWarranty(v)
|
||||
@@ -617,9 +599,6 @@ func (ic *ItemCreate) check() error {
|
||||
if _, ok := ic.mutation.AssetID(); !ok {
|
||||
return &ValidationError{Name: "asset_id", err: errors.New(`ent: missing required field "Item.asset_id"`)}
|
||||
}
|
||||
if _, ok := ic.mutation.SyncChildItemsLocations(); !ok {
|
||||
return &ValidationError{Name: "sync_child_items_locations", err: errors.New(`ent: missing required field "Item.sync_child_items_locations"`)}
|
||||
}
|
||||
if v, ok := ic.mutation.SerialNumber(); ok {
|
||||
if err := item.SerialNumberValidator(v); err != nil {
|
||||
return &ValidationError{Name: "serial_number", err: fmt.Errorf(`ent: validator failed for field "Item.serial_number": %w`, err)}
|
||||
@@ -732,10 +711,6 @@ func (ic *ItemCreate) createSpec() (*Item, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(item.FieldAssetID, field.TypeInt, value)
|
||||
_node.AssetID = value
|
||||
}
|
||||
if value, ok := ic.mutation.SyncChildItemsLocations(); ok {
|
||||
_spec.SetField(item.FieldSyncChildItemsLocations, field.TypeBool, value)
|
||||
_node.SyncChildItemsLocations = value
|
||||
}
|
||||
if value, ok := ic.mutation.SerialNumber(); ok {
|
||||
_spec.SetField(item.FieldSerialNumber, field.TypeString, value)
|
||||
_node.SerialNumber = value
|
||||
|
||||
@@ -185,20 +185,6 @@ func (iu *ItemUpdate) AddAssetID(i int) *ItemUpdate {
|
||||
return iu
|
||||
}
|
||||
|
||||
// SetSyncChildItemsLocations sets the "sync_child_items_locations" field.
|
||||
func (iu *ItemUpdate) SetSyncChildItemsLocations(b bool) *ItemUpdate {
|
||||
iu.mutation.SetSyncChildItemsLocations(b)
|
||||
return iu
|
||||
}
|
||||
|
||||
// SetNillableSyncChildItemsLocations sets the "sync_child_items_locations" field if the given value is not nil.
|
||||
func (iu *ItemUpdate) SetNillableSyncChildItemsLocations(b *bool) *ItemUpdate {
|
||||
if b != nil {
|
||||
iu.SetSyncChildItemsLocations(*b)
|
||||
}
|
||||
return iu
|
||||
}
|
||||
|
||||
// SetSerialNumber sets the "serial_number" field.
|
||||
func (iu *ItemUpdate) SetSerialNumber(s string) *ItemUpdate {
|
||||
iu.mutation.SetSerialNumber(s)
|
||||
@@ -850,9 +836,6 @@ func (iu *ItemUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
if value, ok := iu.mutation.AddedAssetID(); ok {
|
||||
_spec.AddField(item.FieldAssetID, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := iu.mutation.SyncChildItemsLocations(); ok {
|
||||
_spec.SetField(item.FieldSyncChildItemsLocations, field.TypeBool, value)
|
||||
}
|
||||
if value, ok := iu.mutation.SerialNumber(); ok {
|
||||
_spec.SetField(item.FieldSerialNumber, field.TypeString, value)
|
||||
}
|
||||
@@ -1410,20 +1393,6 @@ func (iuo *ItemUpdateOne) AddAssetID(i int) *ItemUpdateOne {
|
||||
return iuo
|
||||
}
|
||||
|
||||
// SetSyncChildItemsLocations sets the "sync_child_items_locations" field.
|
||||
func (iuo *ItemUpdateOne) SetSyncChildItemsLocations(b bool) *ItemUpdateOne {
|
||||
iuo.mutation.SetSyncChildItemsLocations(b)
|
||||
return iuo
|
||||
}
|
||||
|
||||
// SetNillableSyncChildItemsLocations sets the "sync_child_items_locations" field if the given value is not nil.
|
||||
func (iuo *ItemUpdateOne) SetNillableSyncChildItemsLocations(b *bool) *ItemUpdateOne {
|
||||
if b != nil {
|
||||
iuo.SetSyncChildItemsLocations(*b)
|
||||
}
|
||||
return iuo
|
||||
}
|
||||
|
||||
// SetSerialNumber sets the "serial_number" field.
|
||||
func (iuo *ItemUpdateOne) SetSerialNumber(s string) *ItemUpdateOne {
|
||||
iuo.mutation.SetSerialNumber(s)
|
||||
@@ -2105,9 +2074,6 @@ func (iuo *ItemUpdateOne) sqlSave(ctx context.Context) (_node *Item, err error)
|
||||
if value, ok := iuo.mutation.AddedAssetID(); ok {
|
||||
_spec.AddField(item.FieldAssetID, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := iuo.mutation.SyncChildItemsLocations(); ok {
|
||||
_spec.SetField(item.FieldSyncChildItemsLocations, field.TypeBool, value)
|
||||
}
|
||||
if value, ok := iuo.mutation.SerialNumber(); ok {
|
||||
_spec.SetField(item.FieldSerialNumber, field.TypeString, value)
|
||||
}
|
||||
|
||||
@@ -162,7 +162,6 @@ var (
|
||||
{Name: "insured", Type: field.TypeBool, Default: false},
|
||||
{Name: "archived", Type: field.TypeBool, Default: false},
|
||||
{Name: "asset_id", Type: field.TypeInt, Default: 0},
|
||||
{Name: "sync_child_items_locations", Type: field.TypeBool, Default: false},
|
||||
{Name: "serial_number", Type: field.TypeString, Nullable: true, Size: 255},
|
||||
{Name: "model_number", Type: field.TypeString, Nullable: true, Size: 255},
|
||||
{Name: "manufacturer", Type: field.TypeString, Nullable: true, Size: 255},
|
||||
@@ -188,19 +187,19 @@ var (
|
||||
ForeignKeys: []*schema.ForeignKey{
|
||||
{
|
||||
Symbol: "items_groups_items",
|
||||
Columns: []*schema.Column{ItemsColumns[25]},
|
||||
Columns: []*schema.Column{ItemsColumns[24]},
|
||||
RefColumns: []*schema.Column{GroupsColumns[0]},
|
||||
OnDelete: schema.Cascade,
|
||||
},
|
||||
{
|
||||
Symbol: "items_items_children",
|
||||
Columns: []*schema.Column{ItemsColumns[26]},
|
||||
Columns: []*schema.Column{ItemsColumns[25]},
|
||||
RefColumns: []*schema.Column{ItemsColumns[0]},
|
||||
OnDelete: schema.SetNull,
|
||||
},
|
||||
{
|
||||
Symbol: "items_locations_items",
|
||||
Columns: []*schema.Column{ItemsColumns[27]},
|
||||
Columns: []*schema.Column{ItemsColumns[26]},
|
||||
RefColumns: []*schema.Column{LocationsColumns[0]},
|
||||
OnDelete: schema.Cascade,
|
||||
},
|
||||
@@ -214,17 +213,17 @@ var (
|
||||
{
|
||||
Name: "item_manufacturer",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{ItemsColumns[14]},
|
||||
Columns: []*schema.Column{ItemsColumns[13]},
|
||||
},
|
||||
{
|
||||
Name: "item_model_number",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{ItemsColumns[13]},
|
||||
Columns: []*schema.Column{ItemsColumns[12]},
|
||||
},
|
||||
{
|
||||
Name: "item_serial_number",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{ItemsColumns[12]},
|
||||
Columns: []*schema.Column{ItemsColumns[11]},
|
||||
},
|
||||
{
|
||||
Name: "item_archived",
|
||||
|
||||
@@ -4085,7 +4085,6 @@ type ItemMutation struct {
|
||||
archived *bool
|
||||
asset_id *int
|
||||
addasset_id *int
|
||||
sync_child_items_locations *bool
|
||||
serial_number *string
|
||||
model_number *string
|
||||
manufacturer *string
|
||||
@@ -4671,42 +4670,6 @@ func (m *ItemMutation) ResetAssetID() {
|
||||
m.addasset_id = nil
|
||||
}
|
||||
|
||||
// SetSyncChildItemsLocations sets the "sync_child_items_locations" field.
|
||||
func (m *ItemMutation) SetSyncChildItemsLocations(b bool) {
|
||||
m.sync_child_items_locations = &b
|
||||
}
|
||||
|
||||
// SyncChildItemsLocations returns the value of the "sync_child_items_locations" field in the mutation.
|
||||
func (m *ItemMutation) SyncChildItemsLocations() (r bool, exists bool) {
|
||||
v := m.sync_child_items_locations
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldSyncChildItemsLocations returns the old "sync_child_items_locations" field's value of the Item entity.
|
||||
// If the Item object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *ItemMutation) OldSyncChildItemsLocations(ctx context.Context) (v bool, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldSyncChildItemsLocations is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldSyncChildItemsLocations requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldSyncChildItemsLocations: %w", err)
|
||||
}
|
||||
return oldValue.SyncChildItemsLocations, nil
|
||||
}
|
||||
|
||||
// ResetSyncChildItemsLocations resets all changes to the "sync_child_items_locations" field.
|
||||
func (m *ItemMutation) ResetSyncChildItemsLocations() {
|
||||
m.sync_child_items_locations = nil
|
||||
}
|
||||
|
||||
// SetSerialNumber sets the "serial_number" field.
|
||||
func (m *ItemMutation) SetSerialNumber(s string) {
|
||||
m.serial_number = &s
|
||||
@@ -5766,7 +5729,7 @@ func (m *ItemMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *ItemMutation) Fields() []string {
|
||||
fields := make([]string, 0, 24)
|
||||
fields := make([]string, 0, 23)
|
||||
if m.created_at != nil {
|
||||
fields = append(fields, item.FieldCreatedAt)
|
||||
}
|
||||
@@ -5797,9 +5760,6 @@ func (m *ItemMutation) Fields() []string {
|
||||
if m.asset_id != nil {
|
||||
fields = append(fields, item.FieldAssetID)
|
||||
}
|
||||
if m.sync_child_items_locations != nil {
|
||||
fields = append(fields, item.FieldSyncChildItemsLocations)
|
||||
}
|
||||
if m.serial_number != nil {
|
||||
fields = append(fields, item.FieldSerialNumber)
|
||||
}
|
||||
@@ -5867,8 +5827,6 @@ func (m *ItemMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.Archived()
|
||||
case item.FieldAssetID:
|
||||
return m.AssetID()
|
||||
case item.FieldSyncChildItemsLocations:
|
||||
return m.SyncChildItemsLocations()
|
||||
case item.FieldSerialNumber:
|
||||
return m.SerialNumber()
|
||||
case item.FieldModelNumber:
|
||||
@@ -5924,8 +5882,6 @@ func (m *ItemMutation) OldField(ctx context.Context, name string) (ent.Value, er
|
||||
return m.OldArchived(ctx)
|
||||
case item.FieldAssetID:
|
||||
return m.OldAssetID(ctx)
|
||||
case item.FieldSyncChildItemsLocations:
|
||||
return m.OldSyncChildItemsLocations(ctx)
|
||||
case item.FieldSerialNumber:
|
||||
return m.OldSerialNumber(ctx)
|
||||
case item.FieldModelNumber:
|
||||
@@ -6031,13 +5987,6 @@ func (m *ItemMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetAssetID(v)
|
||||
return nil
|
||||
case item.FieldSyncChildItemsLocations:
|
||||
v, ok := value.(bool)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetSyncChildItemsLocations(v)
|
||||
return nil
|
||||
case item.FieldSerialNumber:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
@@ -6340,9 +6289,6 @@ func (m *ItemMutation) ResetField(name string) error {
|
||||
case item.FieldAssetID:
|
||||
m.ResetAssetID()
|
||||
return nil
|
||||
case item.FieldSyncChildItemsLocations:
|
||||
m.ResetSyncChildItemsLocations()
|
||||
return nil
|
||||
case item.FieldSerialNumber:
|
||||
m.ResetSerialNumber()
|
||||
return nil
|
||||
|
||||
@@ -259,40 +259,36 @@ func init() {
|
||||
itemDescAssetID := itemFields[5].Descriptor()
|
||||
// item.DefaultAssetID holds the default value on creation for the asset_id field.
|
||||
item.DefaultAssetID = itemDescAssetID.Default.(int)
|
||||
// itemDescSyncChildItemsLocations is the schema descriptor for sync_child_items_locations field.
|
||||
itemDescSyncChildItemsLocations := itemFields[6].Descriptor()
|
||||
// item.DefaultSyncChildItemsLocations holds the default value on creation for the sync_child_items_locations field.
|
||||
item.DefaultSyncChildItemsLocations = itemDescSyncChildItemsLocations.Default.(bool)
|
||||
// itemDescSerialNumber is the schema descriptor for serial_number field.
|
||||
itemDescSerialNumber := itemFields[7].Descriptor()
|
||||
itemDescSerialNumber := itemFields[6].Descriptor()
|
||||
// item.SerialNumberValidator is a validator for the "serial_number" field. It is called by the builders before save.
|
||||
item.SerialNumberValidator = itemDescSerialNumber.Validators[0].(func(string) error)
|
||||
// itemDescModelNumber is the schema descriptor for model_number field.
|
||||
itemDescModelNumber := itemFields[8].Descriptor()
|
||||
itemDescModelNumber := itemFields[7].Descriptor()
|
||||
// item.ModelNumberValidator is a validator for the "model_number" field. It is called by the builders before save.
|
||||
item.ModelNumberValidator = itemDescModelNumber.Validators[0].(func(string) error)
|
||||
// itemDescManufacturer is the schema descriptor for manufacturer field.
|
||||
itemDescManufacturer := itemFields[9].Descriptor()
|
||||
itemDescManufacturer := itemFields[8].Descriptor()
|
||||
// item.ManufacturerValidator is a validator for the "manufacturer" field. It is called by the builders before save.
|
||||
item.ManufacturerValidator = itemDescManufacturer.Validators[0].(func(string) error)
|
||||
// itemDescLifetimeWarranty is the schema descriptor for lifetime_warranty field.
|
||||
itemDescLifetimeWarranty := itemFields[10].Descriptor()
|
||||
itemDescLifetimeWarranty := itemFields[9].Descriptor()
|
||||
// item.DefaultLifetimeWarranty holds the default value on creation for the lifetime_warranty field.
|
||||
item.DefaultLifetimeWarranty = itemDescLifetimeWarranty.Default.(bool)
|
||||
// itemDescWarrantyDetails is the schema descriptor for warranty_details field.
|
||||
itemDescWarrantyDetails := itemFields[12].Descriptor()
|
||||
itemDescWarrantyDetails := itemFields[11].Descriptor()
|
||||
// item.WarrantyDetailsValidator is a validator for the "warranty_details" field. It is called by the builders before save.
|
||||
item.WarrantyDetailsValidator = itemDescWarrantyDetails.Validators[0].(func(string) error)
|
||||
// itemDescPurchasePrice is the schema descriptor for purchase_price field.
|
||||
itemDescPurchasePrice := itemFields[15].Descriptor()
|
||||
itemDescPurchasePrice := itemFields[14].Descriptor()
|
||||
// item.DefaultPurchasePrice holds the default value on creation for the purchase_price field.
|
||||
item.DefaultPurchasePrice = itemDescPurchasePrice.Default.(float64)
|
||||
// itemDescSoldPrice is the schema descriptor for sold_price field.
|
||||
itemDescSoldPrice := itemFields[18].Descriptor()
|
||||
itemDescSoldPrice := itemFields[17].Descriptor()
|
||||
// item.DefaultSoldPrice holds the default value on creation for the sold_price field.
|
||||
item.DefaultSoldPrice = itemDescSoldPrice.Default.(float64)
|
||||
// itemDescSoldNotes is the schema descriptor for sold_notes field.
|
||||
itemDescSoldNotes := itemFields[19].Descriptor()
|
||||
itemDescSoldNotes := itemFields[18].Descriptor()
|
||||
// item.SoldNotesValidator is a validator for the "sold_notes" field. It is called by the builders before save.
|
||||
item.SoldNotesValidator = itemDescSoldNotes.Validators[0].(func(string) error)
|
||||
// itemDescID is the schema descriptor for id field.
|
||||
|
||||
@@ -51,8 +51,6 @@ func (Item) Fields() []ent.Field {
|
||||
Default(false),
|
||||
field.Int("asset_id").
|
||||
Default(0),
|
||||
field.Bool("sync_child_items_locations").
|
||||
Default(false),
|
||||
|
||||
// ------------------------------------
|
||||
// item identification
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
-- Disable the enforcement of foreign-keys constraints
|
||||
PRAGMA foreign_keys = off;
|
||||
-- Create "new_items" table
|
||||
CREATE TABLE `new_items` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `import_ref` text NULL, `notes` text NULL, `quantity` integer NOT NULL DEFAULT (1), `insured` bool NOT NULL DEFAULT (false), `archived` bool NOT NULL DEFAULT (false), `asset_id` integer NOT NULL DEFAULT (0), `sync_child_items_locations` bool NOT NULL DEFAULT (false), `serial_number` text NULL, `model_number` text NULL, `manufacturer` text NULL, `lifetime_warranty` bool NOT NULL DEFAULT (false), `warranty_expires` datetime NULL, `warranty_details` text NULL, `purchase_time` datetime NULL, `purchase_from` text NULL, `purchase_price` real NOT NULL DEFAULT (0), `sold_time` datetime NULL, `sold_to` text NULL, `sold_price` real NOT NULL DEFAULT (0), `sold_notes` text NULL, `group_items` uuid NOT NULL, `item_children` uuid NULL, `location_items` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `items_groups_items` FOREIGN KEY (`group_items`) REFERENCES `groups` (`id`) ON DELETE CASCADE, CONSTRAINT `items_items_children` FOREIGN KEY (`item_children`) REFERENCES `items` (`id`) ON DELETE SET NULL, CONSTRAINT `items_locations_items` FOREIGN KEY (`location_items`) REFERENCES `locations` (`id`) ON DELETE CASCADE);
|
||||
-- Copy rows from old table "items" to new temporary table "new_items"
|
||||
INSERT INTO `new_items` (`id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `archived`, `asset_id`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `item_children`, `location_items`) SELECT `id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `archived`, `asset_id`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `item_children`, `location_items` FROM `items`;
|
||||
-- Drop "items" table after copying rows
|
||||
DROP TABLE `items`;
|
||||
-- Rename temporary table "new_items" to "items"
|
||||
ALTER TABLE `new_items` RENAME TO `items`;
|
||||
-- Create index "item_name" to table: "items"
|
||||
CREATE INDEX `item_name` ON `items` (`name`);
|
||||
-- Create index "item_manufacturer" to table: "items"
|
||||
CREATE INDEX `item_manufacturer` ON `items` (`manufacturer`);
|
||||
-- Create index "item_model_number" to table: "items"
|
||||
CREATE INDEX `item_model_number` ON `items` (`model_number`);
|
||||
-- Create index "item_serial_number" to table: "items"
|
||||
CREATE INDEX `item_serial_number` ON `items` (`serial_number`);
|
||||
-- Create index "item_archived" to table: "items"
|
||||
CREATE INDEX `item_archived` ON `items` (`archived`);
|
||||
-- Create index "item_asset_id" to table: "items"
|
||||
CREATE INDEX `item_asset_id` ON `items` (`asset_id`);
|
||||
-- Enable back the enforcement of foreign-keys constraints
|
||||
PRAGMA foreign_keys = on;
|
||||
@@ -1,4 +1,4 @@
|
||||
h1:vfyg10T5DT60HhDoHrD7YGmXlGVTOogzumhvxIx4uqw=
|
||||
h1:sjJCTAqc9FG8BKBIzh5ZynYD/Ilz6vnLqM4XX83WQ4M=
|
||||
20220929052825_init.sql h1:ZlCqm1wzjDmofeAcSX3jE4h4VcdTNGpRg2eabztDy9Q=
|
||||
20221001210956_group_invitations.sql h1:YQKJFtE39wFOcRNbZQ/d+ZlHwrcfcsZlcv/pLEYdpjw=
|
||||
20221009173029_add_user_roles.sql h1:vWmzAfgEWQeGk0Vn70zfVPCcfEZth3E0JcvyKTjpYyU=
|
||||
@@ -13,4 +13,3 @@ h1:vfyg10T5DT60HhDoHrD7YGmXlGVTOogzumhvxIx4uqw=
|
||||
20230305065819_add_notifier_types.sql h1:r5xrgCKYQ2o9byBqYeAX1zdp94BLdaxf4vq9OmGHNl0=
|
||||
20230305071524_add_group_id_to_notifiers.sql h1:xDShqbyClcFhvJbwclOHdczgXbdffkxXNWjV61hL/t4=
|
||||
20231006213457_add_primary_attachment_flag.sql h1:J4tMSJQFa7vaj0jpnh8YKTssdyIjRyq6RXDXZIzDDu4=
|
||||
20241226183416_sync_childs.sql h1:RWK0tyu8Wj5ypRceCZWCTEXJQGCjWQMhCUBHUBXGseI=
|
||||
|
||||
@@ -40,7 +40,7 @@ func bootstrap() {
|
||||
}
|
||||
|
||||
func MainNoExit(m *testing.M) int {
|
||||
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1&_time_format=sqlite")
|
||||
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
|
||||
if err != nil {
|
||||
log.Fatalf("failed opening connection to sqlite: %v", err)
|
||||
}
|
||||
|
||||
@@ -67,15 +67,14 @@ type (
|
||||
}
|
||||
|
||||
ItemUpdate struct {
|
||||
ParentID uuid.UUID `json:"parentId" extensions:"x-nullable,x-omitempty"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
AssetID AssetID `json:"assetId" swaggertype:"string"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Description string `json:"description" validate:"max=1000"`
|
||||
Quantity int `json:"quantity"`
|
||||
Insured bool `json:"insured"`
|
||||
Archived bool `json:"archived"`
|
||||
SyncChildItemsLocations bool `json:"syncChildItemsLocations"`
|
||||
ParentID uuid.UUID `json:"parentId" extensions:"x-nullable,x-omitempty"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
AssetID AssetID `json:"assetId" swaggertype:"string"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Description string `json:"description" validate:"max=1000"`
|
||||
Quantity int `json:"quantity"`
|
||||
Insured bool `json:"insured"`
|
||||
Archived bool `json:"archived"`
|
||||
|
||||
// Edges
|
||||
LocationID uuid.UUID `json:"locationId"`
|
||||
@@ -93,12 +92,12 @@ type (
|
||||
|
||||
// Purchase
|
||||
PurchaseTime types.Date `json:"purchaseTime"`
|
||||
PurchaseFrom string `json:"purchaseFrom" validate:"max=255"`
|
||||
PurchaseFrom string `json:"purchaseFrom" validate:"max=255"`
|
||||
PurchasePrice float64 `json:"purchasePrice" extensions:"x-nullable,x-omitempty"`
|
||||
|
||||
// Sold
|
||||
SoldTime types.Date `json:"soldTime"`
|
||||
SoldTo string `json:"soldTo" validate:"max=255"`
|
||||
SoldTo string `json:"soldTo" validate:"max=255"`
|
||||
SoldPrice float64 `json:"soldPrice" extensions:"x-nullable,x-omitempty"`
|
||||
SoldNotes string `json:"soldNotes"`
|
||||
|
||||
@@ -116,7 +115,6 @@ type (
|
||||
ItemSummary struct {
|
||||
ImportRef string `json:"-"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
AssetID AssetID `json:"assetId,string"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Quantity int `json:"quantity"`
|
||||
@@ -139,8 +137,6 @@ type (
|
||||
ItemSummary
|
||||
AssetID AssetID `json:"assetId,string"`
|
||||
|
||||
SyncChildItemsLocations bool `json:"syncChildItemsLocations"`
|
||||
|
||||
SerialNumber string `json:"serialNumber"`
|
||||
ModelNumber string `json:"modelNumber"`
|
||||
Manufacturer string `json:"manufacturer"`
|
||||
@@ -194,7 +190,6 @@ func mapItemSummary(item *ent.Item) ItemSummary {
|
||||
|
||||
return ItemSummary{
|
||||
ID: item.ID,
|
||||
AssetID: AssetID(item.AssetID),
|
||||
Name: item.Name,
|
||||
Description: item.Description,
|
||||
ImportRef: item.ImportRef,
|
||||
@@ -253,13 +248,12 @@ func mapItemOut(item *ent.Item) ItemOut {
|
||||
}
|
||||
|
||||
return ItemOut{
|
||||
Parent: parent,
|
||||
AssetID: AssetID(item.AssetID),
|
||||
ItemSummary: mapItemSummary(item),
|
||||
LifetimeWarranty: item.LifetimeWarranty,
|
||||
WarrantyExpires: types.DateFromTime(item.WarrantyExpires),
|
||||
WarrantyDetails: item.WarrantyDetails,
|
||||
SyncChildItemsLocations: item.SyncChildItemsLocations,
|
||||
Parent: parent,
|
||||
AssetID: AssetID(item.AssetID),
|
||||
ItemSummary: mapItemSummary(item),
|
||||
LifetimeWarranty: item.LifetimeWarranty,
|
||||
WarrantyExpires: types.DateFromTime(item.WarrantyExpires),
|
||||
WarrantyDetails: item.WarrantyDetails,
|
||||
|
||||
// Identification
|
||||
SerialNumber: item.SerialNumber,
|
||||
@@ -428,8 +422,6 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite
|
||||
qb = qb.Order(ent.Desc(item.FieldCreatedAt))
|
||||
case "updatedAt":
|
||||
qb = qb.Order(ent.Desc(item.FieldUpdatedAt))
|
||||
case "assetId":
|
||||
qb = qb.Order(ent.Asc(item.FieldAssetID))
|
||||
default: // "name"
|
||||
qb = qb.Order(ent.Asc(item.FieldName))
|
||||
}
|
||||
@@ -614,8 +606,7 @@ func (e *ItemsRepository) UpdateByGroup(ctx context.Context, gid uuid.UUID, data
|
||||
SetWarrantyExpires(data.WarrantyExpires.Time()).
|
||||
SetWarrantyDetails(data.WarrantyDetails).
|
||||
SetQuantity(data.Quantity).
|
||||
SetAssetID(int(data.AssetID)).
|
||||
SetSyncChildItemsLocations(data.SyncChildItemsLocations)
|
||||
SetAssetID(int(data.AssetID))
|
||||
|
||||
currentLabels, err := e.db.Item.Query().Where(item.ID(data.ID)).QueryLabel().All(ctx)
|
||||
if err != nil {
|
||||
@@ -642,28 +633,6 @@ func (e *ItemsRepository) UpdateByGroup(ctx context.Context, gid uuid.UUID, data
|
||||
q.ClearParent()
|
||||
}
|
||||
|
||||
if data.SyncChildItemsLocations {
|
||||
children, err := e.db.Item.Query().Where(item.ID(data.ID)).QueryChildren().All(ctx)
|
||||
if err != nil {
|
||||
return ItemOut{}, err
|
||||
}
|
||||
location := data.LocationID
|
||||
|
||||
for _, child := range children {
|
||||
childLocation, err := child.QueryLocation().First(ctx)
|
||||
if err != nil {
|
||||
return ItemOut{}, err
|
||||
}
|
||||
|
||||
if location != childLocation.ID {
|
||||
err = child.Update().SetLocationID(location).Exec(ctx)
|
||||
if err != nil {
|
||||
return ItemOut{}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = q.Exec(ctx)
|
||||
if err != nil {
|
||||
return ItemOut{}, err
|
||||
|
||||
@@ -164,9 +164,7 @@ func (r *LocationRepository) getOne(ctx context.Context, where ...predicate.Loca
|
||||
Where(where...).
|
||||
WithGroup().
|
||||
WithParent().
|
||||
WithChildren(func(lq *ent.LocationQuery) {
|
||||
lq.Order(location.ByName())
|
||||
}).
|
||||
WithChildren().
|
||||
Only(ctx))
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sysadminsmedia/homebox/backend/internal/data/ent"
|
||||
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/group"
|
||||
@@ -131,36 +130,19 @@ func (r *MaintenanceEntryRepository) GetMaintenanceByItemID(ctx context.Context,
|
||||
item.HasGroupWith(group.IDEQ(groupID)),
|
||||
),
|
||||
)
|
||||
switch filters.Status {
|
||||
case MaintenanceFilterStatusScheduled:
|
||||
if filters.Status == MaintenanceFilterStatusScheduled {
|
||||
query = query.Where(maintenanceentry.Or(
|
||||
maintenanceentry.DateIsNil(),
|
||||
maintenanceentry.DateEQ(time.Time{}),
|
||||
maintenanceentry.DateGT(time.Now()),
|
||||
))
|
||||
// Sort scheduled entries by ascending scheduled date
|
||||
query = query.Order(
|
||||
maintenanceentry.ByScheduledDate(sql.OrderAsc()),
|
||||
)
|
||||
case MaintenanceFilterStatusCompleted:
|
||||
} else if filters.Status == MaintenanceFilterStatusCompleted {
|
||||
query = query.Where(
|
||||
maintenanceentry.Not(maintenanceentry.Or(
|
||||
maintenanceentry.DateIsNil(),
|
||||
maintenanceentry.DateEQ(time.Time{}),
|
||||
maintenanceentry.DateGT(time.Now()),
|
||||
)))
|
||||
// Sort completed entries by descending completion date
|
||||
query = query.Order(
|
||||
maintenanceentry.ByDate(sql.OrderDesc()),
|
||||
)
|
||||
default:
|
||||
// Sort entries by default by scheduled and maintenance date in descending order
|
||||
query = query.Order(
|
||||
maintenanceentry.ByScheduledDate(sql.OrderDesc()),
|
||||
maintenanceentry.ByDate(sql.OrderDesc()),
|
||||
)
|
||||
maintenanceentry.DateEQ(time.Time{})),
|
||||
))
|
||||
}
|
||||
entries, err := query.WithItem().All(ctx)
|
||||
entries, err := query.WithItem().Order(maintenanceentry.ByScheduledDate()).All(ctx)
|
||||
|
||||
if err != nil {
|
||||
return []MaintenanceEntryWithDetails{}, err
|
||||
|
||||
@@ -32,8 +32,8 @@ func getPrevMonth(now time.Time) time.Time {
|
||||
func TestMaintenanceEntryRepository_GetLog(t *testing.T) {
|
||||
item := useItems(t, 1)[0]
|
||||
|
||||
// Create 11 maintenance entries for the item
|
||||
created := make([]MaintenanceEntryCreate, 11)
|
||||
// Create 10 maintenance entries for the item
|
||||
created := make([]MaintenanceEntryCreate, 10)
|
||||
|
||||
thisMonth := time.Now()
|
||||
lastMonth := getPrevMonth(thisMonth)
|
||||
@@ -52,14 +52,6 @@ func TestMaintenanceEntryRepository_GetLog(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add an entry completed in the future
|
||||
created[10] = MaintenanceEntryCreate{
|
||||
CompletedDate: types.DateFromTime(time.Now().AddDate(0, 0, 1)),
|
||||
Name: "Maintenance",
|
||||
Description: "Maintenance description",
|
||||
Cost: 10,
|
||||
}
|
||||
|
||||
for _, entry := range created {
|
||||
_, err := tRepos.MaintEntry.Create(context.Background(), item.ID, entry)
|
||||
if err != nil {
|
||||
|
||||
@@ -32,7 +32,6 @@ type Options struct {
|
||||
AllowRegistration bool `yaml:"disable_registration" conf:"default:true"`
|
||||
AutoIncrementAssetID bool `yaml:"auto_increment_asset_id" conf:"default:true"`
|
||||
CurrencyConfig string `yaml:"currencies"`
|
||||
GithubReleaseCheck bool `yaml:"check_github_release" conf:"default:true"`
|
||||
}
|
||||
|
||||
type DebugConf struct {
|
||||
|
||||
@@ -7,5 +7,5 @@ const (
|
||||
type Storage struct {
|
||||
// Data is the path to the root directory
|
||||
Data string `yaml:"data" conf:"default:./.data"`
|
||||
SqliteURL string `yaml:"sqlite-url" conf:"default:./.data/homebox.db?_pragma=busy_timeout=999&_pragma=journal_mode=WAL&_fk=1&_time_format=sqlite"`
|
||||
SqliteURL string `yaml:"sqlite-url" conf:"default:./.data/homebox.db?_pragma=busy_timeout=999&_pragma=journal_mode=WAL&_fk=1"`
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export default defineConfig({
|
||||
},
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
{ text: 'API Docs', link: '/en/api' },
|
||||
{ text: 'API', link: 'https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/sysadminsmedia/homebox/main/docs/docs/api/openapi-2.0.json' },
|
||||
{ text: 'Demo', link: 'https://demo.homebox.software' },
|
||||
],
|
||||
|
||||
|
||||
@@ -559,9 +559,6 @@
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"multipart/form-data"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -733,9 +730,6 @@
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"multipart/form-data"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -920,13 +914,6 @@
|
||||
],
|
||||
"summary": "Get Maintenance Log",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Item ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"scheduled",
|
||||
@@ -969,13 +956,6 @@
|
||||
],
|
||||
"summary": "Create Maintenance Entry",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Item ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Entry Data",
|
||||
"name": "payload",
|
||||
@@ -1447,13 +1427,6 @@
|
||||
],
|
||||
"summary": "Update Maintenance Entry",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Maintenance ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Entry Data",
|
||||
"name": "payload",
|
||||
@@ -1486,15 +1459,6 @@
|
||||
"Maintenance"
|
||||
],
|
||||
"summary": "Delete Maintenance Entry",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Maintenance ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
@@ -1577,6 +1541,13 @@
|
||||
],
|
||||
"summary": "Test Notifier",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Notifier ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "URL",
|
||||
@@ -1774,6 +1745,20 @@
|
||||
],
|
||||
"summary": "User Login",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"example": "admin@admin.com",
|
||||
"description": "string",
|
||||
"name": "username",
|
||||
"in": "formData"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"example": "admin",
|
||||
"description": "string",
|
||||
"name": "password",
|
||||
"in": "formData"
|
||||
},
|
||||
{
|
||||
"description": "Login Data",
|
||||
"name": "payload",
|
||||
@@ -2250,9 +2235,6 @@
|
||||
"soldTo": {
|
||||
"type": "string"
|
||||
},
|
||||
"syncChildItemsLocations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2297,10 +2279,6 @@
|
||||
"archived": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"assetId": {
|
||||
"type": "string",
|
||||
"example": "0"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2455,9 +2433,6 @@
|
||||
"type": "string",
|
||||
"maxLength": 255
|
||||
},
|
||||
"syncChildItemsLocations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"warrantyDetails": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2943,17 +2918,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"services.Latest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"date": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"services.UserRegistration": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2986,9 +2950,6 @@
|
||||
"health": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"latest": {
|
||||
"$ref": "#/definitions/services.Latest"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3078,15 +3039,13 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string",
|
||||
"example": "admin"
|
||||
"type": "string"
|
||||
},
|
||||
"stayLoggedIn": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"example": "admin@admin.com"
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
---
|
||||
layout: page
|
||||
sidebar: false
|
||||
---
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useData } from 'vitepress';
|
||||
|
||||
const elementScript = document.createElement('script');
|
||||
elementScript.src = 'https://unpkg.com/@stoplight/elements/web-components.min.js';
|
||||
document.head.appendChild(elementScript);
|
||||
|
||||
const elementStyle = document.createElement('link');
|
||||
elementStyle.rel = 'stylesheet';
|
||||
elementStyle.href = 'https://unpkg.com/@stoplight/elements/styles.min.css';
|
||||
document.head.appendChild(elementStyle);
|
||||
|
||||
const { isDark } = useData();
|
||||
let theme = 'light';
|
||||
if (isDark.value) {
|
||||
theme = 'dark';
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.TryItPanel {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<elements-api
|
||||
apiDescriptionUrl="https://cdn.jsdelivr.net/gh/sysadminsmedia/homebox@main/docs/docs/api/openapi-2.0.json"
|
||||
router="hash"
|
||||
layout="responsive"
|
||||
hideSchemas="true"
|
||||
:data-theme="theme"
|
||||
/>
|
||||
@@ -2,30 +2,29 @@
|
||||
|
||||
## Env Variables & Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
|--------------------------------------|--------------------------------------------|----------------------------------------------------------------------------------------|
|
||||
| HBOX_MODE | `production` | application mode used for runtime behavior can be one of: `development`, `production` |
|
||||
| HBOX_WEB_PORT | 7745 | port to run the web server on, if you're using docker do not change this |
|
||||
| HBOX_WEB_HOST | | host to run the web server on, if you're using docker do not change this |
|
||||
| HBOX_OPTIONS_ALLOW_REGISTRATION | true | allow users to register themselves |
|
||||
| HBOX_OPTIONS_AUTO_INCREMENT_ASSET_ID | true | auto-increments the asset_id field for new items |
|
||||
| HBOX_OPTIONS_CURRENCY_CONFIG | | json configuration file containing additional currencie |
|
||||
| HBOX_WEB_MAX_FILE_UPLOAD | 10 | maximum file upload size supported in MB |
|
||||
| HBOX_WEB_READ_TIMEOUT | 10s | Read timeout of HTTP sever |
|
||||
| HBOX_WEB_WRITE_TIMEOUT | 10s | Write timeout of HTTP server |
|
||||
| HBOX_WEB_IDLE_TIMEOUT | 30s | Idle timeout of HTTP server |
|
||||
| HBOX_STORAGE_DATA | /data/ | path to the data directory, do not change this if you're using docker |
|
||||
| HBOX_STORAGE_SQLITE_URL | /data/homebox.db?_fk=1&_time_format=sqlite | sqlite database url, if you're using docker do not change this |
|
||||
| HBOX_LOG_LEVEL | `info` | log level to use, can be one of `trace`, `debug`, `info`, `warn`, `error`, `critical` |
|
||||
| HBOX_LOG_FORMAT | `text` | log format to use, can be one of: `text`, `json` |
|
||||
| HBOX_MAILER_HOST | | email host to use, if not set no email provider will be used |
|
||||
| HBOX_MAILER_PORT | 587 | email port to use |
|
||||
| HBOX_MAILER_USERNAME | | email user to use |
|
||||
| HBOX_MAILER_PASSWORD | | email password to use |
|
||||
| HBOX_MAILER_FROM | | email from address to use |
|
||||
| HBOX_SWAGGER_HOST | 7745 | swagger host to use, if not set swagger will be disabled |
|
||||
| HBOX_SWAGGER_SCHEMA | `http` | swagger schema to use, can be one of: `http`, `https` |
|
||||
| HBOX_OPTIONS_CHECK_GITHUB_RELEASE | true | check for new github releases |
|
||||
| Variable | Default | Description |
|
||||
| ------------------------------------ | ---------------------- | ---------------------------------------------------------------------------------- |
|
||||
| HBOX_MODE | `production` | application mode used for runtime behavior can be one of: `development`, `production` |
|
||||
| HBOX_WEB_PORT | 7745 | port to run the web server on, if you're using docker do not change this |
|
||||
| HBOX_WEB_HOST | | host to run the web server on, if you're using docker do not change this |
|
||||
| HBOX_OPTIONS_ALLOW_REGISTRATION | true | allow users to register themselves |
|
||||
| HBOX_OPTIONS_AUTO_INCREMENT_ASSET_ID | true | auto-increments the asset_id field for new items |
|
||||
| HBOX_OPTIONS_CURRENCY_CONFIG | | json configuration file containing additional currencie |
|
||||
| HBOX_WEB_MAX_UPLOAD_SIZE | 10 | maximum file upload size supported in MB |
|
||||
| HBOX_WEB_READ_TIMEOUT | 10s | Read timeout of HTTP sever |
|
||||
| HBOX_WEB_WRITE_TIMEOUT | 10s | Write timeout of HTTP server |
|
||||
| HBOX_WEB_IDLE_TIMEOUT | 30s | Idle timeout of HTTP server |
|
||||
| HBOX_STORAGE_DATA | /data/ | path to the data directory, do not change this if you're using docker |
|
||||
| HBOX_STORAGE_SQLITE_URL | /data/homebox.db?_fk=1 | sqlite database url, if you're using docker do not change this |
|
||||
| HBOX_LOG_LEVEL | `info` | log level to use, can be one of `trace`, `debug`, `info`, `warn`, `error`, `critical` |
|
||||
| HBOX_LOG_FORMAT | `text` | log format to use, can be one of: `text`, `json` |
|
||||
| HBOX_MAILER_HOST | | email host to use, if not set no email provider will be used |
|
||||
| HBOX_MAILER_PORT | 587 | email port to use |
|
||||
| HBOX_MAILER_USERNAME | | email user to use |
|
||||
| HBOX_MAILER_PASSWORD | | email password to use |
|
||||
| HBOX_MAILER_FROM | | email from address to use |
|
||||
| HBOX_SWAGGER_HOST | 7745 | swagger host to use, if not set swagger will be disabled |
|
||||
| HBOX_SWAGGER_SCHEMA | `http` | swagger schema to use, can be one of: `http`, `https` |
|
||||
|
||||
::: tip "CLI Arguments"
|
||||
If you're deploying without docker you can use command line arguments to configure the application. Run `homebox --help` for more information.
|
||||
@@ -37,9 +36,9 @@ OPTIONS
|
||||
--mode/$HBOX_MODE <string> (default: development)
|
||||
--web-port/$HBOX_WEB_PORT <string> (default: 7745)
|
||||
--web-host/$HBOX_WEB_HOST <string>
|
||||
--web-max-file-upload/$HBOX_WEB_MAX_FILE_UPLOAD <int> (default: 10)
|
||||
--web-max-upload-size/$HBOX_WEB_MAX_UPLOAD_SIZE <int> (default: 10)
|
||||
--storage-data/$HBOX_STORAGE_DATA <string> (default: ./.data)
|
||||
--storage-sqlite-url/$HBOX_STORAGE_SQLITE_URL <string> (default: ./.data/homebox.db?_fk=1&_time_format=sqlite)
|
||||
--storage-sqlite-url/$HBOX_STORAGE_SQLITE_URL <string> (default: ./.data/homebox.db?_fk=1)
|
||||
--log-level/$HBOX_LOG_LEVEL <string> (default: info)
|
||||
--log-format/$HBOX_LOG_FORMAT <string> (default: text)
|
||||
--mailer-host/$HBOX_MAILER_HOST <string>
|
||||
@@ -55,7 +54,6 @@ OPTIONS
|
||||
--options-allow-registration/$HBOX_OPTIONS_ALLOW_REGISTRATION <bool> (default: true)
|
||||
--options-auto-increment-asset-id/$HBOX_OPTIONS_AUTO_INCREMENT_ASSET_ID <bool> (default: true)
|
||||
--options-currency-config/$HBOX_OPTIONS_CURRENCY_CONFIG <string>
|
||||
--options-check-github-release/$HBOX_OPTIONS_CHECK_GITHUB_RELEASE <bool> (default: true)
|
||||
--help/-h display this help message
|
||||
```
|
||||
:::
|
||||
|
||||
@@ -82,11 +82,3 @@ Homebox allows you to add additional currencies to your instance by specify a JS
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
## Copy to Clipboard
|
||||
|
||||
The copy to clipboard functionality requires a secure context (HTTPS or localhost) to work due to browser security restrictions. If you're accessing Homebox through HTTP, the copy button will not function.
|
||||
|
||||
To enable this feature:
|
||||
- Use HTTPS by setting up a reverse proxy (like Nginx or Caddy)
|
||||
- OR access Homebox through localhost
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<template>
|
||||
<BaseModal v-model="modal">
|
||||
<template #title>🎉 {{ $t("components.app.outdated.new_version_available") }} 🎉</template>
|
||||
<div class="p-4">
|
||||
<p>{{ $t("components.app.outdated.current_version") }}: {{ current }}</p>
|
||||
<p>{{ $t("components.app.outdated.latest_version") }}: {{ latest }}</p>
|
||||
<p>
|
||||
<a href="https://github.com/sysadminsmedia/homebox/releases" target="_blank" rel="noopener" class="link">
|
||||
{{ $t("components.app.outdated.new_version_available_link") }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<button class="btn btn-warning" @click="hide">
|
||||
{{ $t("components.app.outdated.dismiss") }}
|
||||
</button>
|
||||
</BaseModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
current: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
latest: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const modal = useVModel(props, "modelValue");
|
||||
|
||||
const hide = () => {
|
||||
modal.value = false;
|
||||
localStorage.setItem("latestVersion", props.latest);
|
||||
};
|
||||
</script>
|
||||
@@ -3,27 +3,13 @@
|
||||
<label class="label">
|
||||
<span class="label-text"> {{ label }} </span>
|
||||
</label>
|
||||
<VueDatePicker
|
||||
v-model="selected"
|
||||
:enable-time-picker="false"
|
||||
clearable
|
||||
:dark="isDark"
|
||||
:teleport="true"
|
||||
:format="formatDate"
|
||||
/>
|
||||
<VueDatePicker v-model="selected" :enable-time-picker="false" clearable :dark="isDark" :teleport="true" />
|
||||
</div>
|
||||
<div v-else class="sm:grid sm:grid-cols-4 sm:items-start sm:gap-4">
|
||||
<label class="label">
|
||||
<span class="label-text"> {{ label }} </span>
|
||||
</label>
|
||||
<VueDatePicker
|
||||
v-model="selected"
|
||||
:enable-time-picker="false"
|
||||
clearable
|
||||
:dark="isDark"
|
||||
:teleport="true"
|
||||
:format="formatDate"
|
||||
/>
|
||||
<VueDatePicker v-model="selected" :enable-time-picker="false" clearable :dark="isDark" :teleport="true" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -52,8 +38,6 @@
|
||||
|
||||
const isDark = useIsDark();
|
||||
|
||||
const formatDate = (date: Date | string | number) => fmtDate(date, "human", "date");
|
||||
|
||||
const selected = computed<Date | null>({
|
||||
get() {
|
||||
// String
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
</label>
|
||||
<div class="dropdown dropdown-top sm:dropdown-end">
|
||||
<div tabindex="0" class="flex min-h-[48px] w-full flex-wrap gap-2 rounded-lg border border-gray-400 p-4">
|
||||
<span v-for="itm in value" :key="itm.id" class="badge">
|
||||
{{ itm.name }}
|
||||
<span v-for="itm in value" :key="name != '' ? itm[name] : itm" class="badge">
|
||||
{{ name != "" ? itm[name] : itm }}
|
||||
</span>
|
||||
<button
|
||||
v-if="value.length > 0"
|
||||
@@ -20,7 +20,7 @@
|
||||
<div
|
||||
tabindex="0"
|
||||
style="display: inline"
|
||||
class="dropdown-content menu bg-base-100 z-[9999] mb-1 w-full rounded border border-gray-400 shadow"
|
||||
class="dropdown-content menu z-[9999] mb-1 w-full rounded border border-gray-400 bg-base-100 shadow"
|
||||
>
|
||||
<div class="m-2">
|
||||
<input v-model="search" placeholder="Search…" class="input input-bordered input-sm w-full" />
|
||||
@@ -30,16 +30,13 @@
|
||||
v-for="(obj, idx) in filteredItems"
|
||||
:key="idx"
|
||||
:class="{
|
||||
bordered: selected.includes(obj.id),
|
||||
bordered: selected.includes(obj[props.uniqueField]),
|
||||
}"
|
||||
>
|
||||
<button type="button" @click="toggle(obj.id)">
|
||||
{{ obj.name }}
|
||||
<button type="button" @click="toggle(obj[props.uniqueField])">
|
||||
{{ name != "" ? obj[name] : obj }}
|
||||
</button>
|
||||
</li>
|
||||
<li v-if="!filteredItems.some(itm => itm.name === search) && search.length > 0">
|
||||
<button type="button" @click="createAndAdd(search)">{{ $t("global.create") }} {{ search }}</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,6 +60,14 @@
|
||||
type: Array as () => any[],
|
||||
required: true,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: "name",
|
||||
},
|
||||
uniqueField: {
|
||||
type: String,
|
||||
default: "id",
|
||||
},
|
||||
selectFirst: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -79,7 +84,7 @@
|
||||
}
|
||||
|
||||
return props.items.filter(item => {
|
||||
return item.name.toLowerCase().includes(search.value.toLowerCase());
|
||||
return item[props.name].toLowerCase().includes(search.value.toLowerCase());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -88,33 +93,15 @@
|
||||
}
|
||||
|
||||
const selected = computed<string[]>(() => {
|
||||
return value.value.map(itm => itm.id);
|
||||
return value.value.map(itm => itm[props.uniqueField]);
|
||||
});
|
||||
|
||||
function toggle(uniqueField: string) {
|
||||
const item = props.items.find(itm => itm.id === uniqueField);
|
||||
if (selected.value.includes(item.id)) {
|
||||
value.value = value.value.filter(itm => itm.id !== item.id);
|
||||
const item = props.items.find(itm => itm[props.uniqueField] === uniqueField);
|
||||
if (selected.value.includes(item[props.uniqueField])) {
|
||||
value.value = value.value.filter(itm => itm[props.uniqueField] !== item[props.uniqueField]);
|
||||
} else {
|
||||
value.value = [...value.value, item];
|
||||
}
|
||||
}
|
||||
|
||||
const api = useUserApi();
|
||||
const toast = useNotifier();
|
||||
|
||||
async function createAndAdd(name: string) {
|
||||
const { error, data } = await api.labels.create({
|
||||
name,
|
||||
color: "", // Future!
|
||||
description: "",
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error(error);
|
||||
toast.error(`Failed to create label: ${name}`);
|
||||
} else {
|
||||
value.value = [...value.value, data];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<div v-if="!inline" class="form-control w-full">
|
||||
<label class="label cursor-pointer">
|
||||
<input v-model="value" type="checkbox" class="toggle toggle-primary" />
|
||||
<span class="label-text"> {{ label }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div v-else class="label cursor-pointer sm:grid sm:grid-cols-4 sm:items-start sm:gap-4">
|
||||
<label>
|
||||
<span class="label-text">
|
||||
{{ label }}
|
||||
</span>
|
||||
</label>
|
||||
<input v-model="value" type="checkbox" class="toggle toggle-primary" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
const value = useVModel(props, "modelValue");
|
||||
</script>
|
||||
@@ -14,7 +14,7 @@
|
||||
:to="`/location/${item.location.id}`"
|
||||
loading="lazy"
|
||||
>
|
||||
{{ locationString }}
|
||||
{{ item.location.name }}
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,16 +67,7 @@
|
||||
type: Object as () => ItemOut | ItemSummary,
|
||||
required: true,
|
||||
},
|
||||
locationFlatTree: {
|
||||
type: Array as () => FlatTreeItem[],
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const locationString = computed(
|
||||
() => props.locationFlatTree.find(l => l.id === props.item.location?.id)?.treeString || props.item.location?.name
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="css"></style>
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
<BaseSectionHeader class="border-b border-b-gray-300 p-6">
|
||||
<span class="text-base-content">
|
||||
<span v-if="!props.currentItemId">
|
||||
<NuxtLink class="hover:underline" :to="`/item/${(e as MaintenanceEntryWithDetails).itemID}/maintenance`">
|
||||
<NuxtLink class="hover:underline" :to="`/item/${(e as MaintenanceEntryWithDetails).itemID}`">
|
||||
{{ (e as MaintenanceEntryWithDetails).itemName }}
|
||||
</NuxtLink>
|
||||
-
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<button @click="copyText">
|
||||
<button class="" @click="copyText">
|
||||
<label
|
||||
class="swap swap-rotate"
|
||||
:class="{
|
||||
@@ -21,27 +21,6 @@
|
||||
}"
|
||||
/>
|
||||
</label>
|
||||
<Teleport to="#app">
|
||||
<BaseModal v-model="copyError">
|
||||
<div class="space-y-2">
|
||||
<p>
|
||||
{{ $t("components.global.copy_text.failed_to_copy") }}
|
||||
{{ isNotHttps ? $t("components.global.copy_text.https_required") : "" }}
|
||||
</p>
|
||||
<p class="text-sm">
|
||||
{{ $t("components.global.copy_text.learn_more") }}
|
||||
<a
|
||||
href="https://homebox.software/en/tips-tricks.html#copy-to-clipboard"
|
||||
class="text-primary hover:underline"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
{{ $t("components.global.copy_text.documentation") }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</BaseModal></Teleport
|
||||
>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
@@ -60,15 +39,16 @@
|
||||
},
|
||||
});
|
||||
|
||||
const { copy, copied } = useClipboard({ source: props.text, copiedDuring: 1000 });
|
||||
const copyError = ref(false);
|
||||
const isNotHttps = window.location.protocol !== "https:";
|
||||
const copied = ref(false);
|
||||
|
||||
async function copyText() {
|
||||
await copy(props.text);
|
||||
if (!copied.value) {
|
||||
console.error(`Failed to copy to clipboard${isNotHttps ? " likely because protocol is not https" : ""}`);
|
||||
copyError.value = true;
|
||||
}
|
||||
const { copy } = useClipboard();
|
||||
|
||||
function copyText() {
|
||||
copy(props.text);
|
||||
copied.value = true;
|
||||
|
||||
setTimeout(() => {
|
||||
copied.value = false;
|
||||
}, 1000);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -22,6 +22,6 @@
|
||||
return "";
|
||||
}
|
||||
|
||||
return fmtDate(props.date, props.format, props.datetimeType);
|
||||
return fmtDate(props.date, props.format);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { format, formatDistance } from "date-fns";
|
||||
/* eslint import/namespace: ['error', { allowComputed: true }] */
|
||||
import * as Locales from "date-fns/locale";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { type UseTimeAgoMessages, type UseTimeAgoUnitNamesDefault } from "@vueuse/core";
|
||||
|
||||
const cache = {
|
||||
currency: "",
|
||||
@@ -21,63 +20,105 @@ export async function useFormatCurrency() {
|
||||
}
|
||||
}
|
||||
|
||||
return (value: number | string) => fmtCurrency(value, cache.currency, getLocaleCode());
|
||||
return (value: number | string) => fmtCurrency(value, cache.currency);
|
||||
}
|
||||
|
||||
export type DateTimeFormat = "relative" | "long" | "short" | "human";
|
||||
export type DateTimeType = "date" | "time" | "datetime";
|
||||
|
||||
export function getLocaleCode() {
|
||||
const { $i18nGlobal } = useNuxtApp();
|
||||
return ($i18nGlobal?.locale?.value as string) ?? "en-US";
|
||||
function ordinalIndicator(num: number) {
|
||||
if (num > 3 && num < 21) return "th";
|
||||
switch (num % 10) {
|
||||
case 1:
|
||||
return "st";
|
||||
case 2:
|
||||
return "nd";
|
||||
case 3:
|
||||
return "rd";
|
||||
default:
|
||||
return "th";
|
||||
}
|
||||
}
|
||||
|
||||
function getLocaleForDate() {
|
||||
const localeCode = getLocaleCode();
|
||||
const lang = localeCode.length > 1 ? localeCode.substring(0, 2) : localeCode;
|
||||
const region = localeCode.length > 2 ? localeCode.substring(3) : "";
|
||||
return Locales[(lang + region) as keyof typeof Locales] ?? Locales[lang as keyof typeof Locales] ?? Locales.enUS;
|
||||
export function useLocaleTimeAgo(date: Date) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const I18N_MESSAGES: UseTimeAgoMessages<UseTimeAgoUnitNamesDefault> = {
|
||||
justNow: t("components.global.date_time.just-now"),
|
||||
past: n => (n.match(/\d/) ? t("components.global.date_time.ago", [n]) : n),
|
||||
future: n => (n.match(/\d/) ? t("components.global.date_time.in", [n]) : n),
|
||||
month: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.last-month")
|
||||
: t("components.global.date_time.next-month")
|
||||
: `${n} ${t(`components.global.date_time.months`)}`,
|
||||
year: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.last-year")
|
||||
: t("components.global.date_time.next-year")
|
||||
: `${n} ${t(`components.global.date_time.years`)}`,
|
||||
day: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.yesterday")
|
||||
: t("components.global.date_time.tomorrow")
|
||||
: `${n} ${t(`components.global.date_time.days`)}`,
|
||||
week: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.last-week")
|
||||
: t("components.global.date_time.next-week")
|
||||
: `${n} ${t(`components.global.date_time.weeks`)}`,
|
||||
hour: n => `${n} ${n === 1 ? t("components.global.date_time.hour") : t("components.global.date_time.hours")}`,
|
||||
minute: n => `${n} ${n === 1 ? t("components.global.date_time.minute") : t("components.global.date_time.minutes")}`,
|
||||
second: n => `${n} ${n === 1 ? t("components.global.date_time.second") : t("components.global.date_time.seconds")}`,
|
||||
invalid: "",
|
||||
};
|
||||
|
||||
return useTimeAgo(date, {
|
||||
fullDateFormatter: (date: Date) => date.toLocaleDateString(),
|
||||
messages: I18N_MESSAGES,
|
||||
});
|
||||
}
|
||||
|
||||
export function fmtDate(
|
||||
value: string | Date | number,
|
||||
fmt: DateTimeFormat = "human",
|
||||
type: DateTimeType = "date"
|
||||
): string {
|
||||
const dt = typeof value === "string" || typeof value === "number" ? new Date(value) : value;
|
||||
export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human"): string {
|
||||
const months = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
];
|
||||
|
||||
if (!dt || !validDate(dt)) {
|
||||
const dt = typeof value === "string" ? new Date(value) : value;
|
||||
if (!dt) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const localeOptions = { locale: getLocaleForDate() };
|
||||
|
||||
if (fmt === "relative") {
|
||||
return `${formatDistance(dt, new Date(), { ...localeOptions, addSuffix: true })} (${fmtDate(dt, "short", "date")})`;
|
||||
if (!validDate(dt)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (type === "time") {
|
||||
return format(dt, "p", localeOptions);
|
||||
}
|
||||
|
||||
let formatStr = "";
|
||||
|
||||
switch (fmt) {
|
||||
case "human":
|
||||
formatStr = "PPP";
|
||||
break;
|
||||
case "relative":
|
||||
return useLocaleTimeAgo(dt).value + useDateFormat(dt, " (YYYY-MM-DD)").value;
|
||||
case "long":
|
||||
formatStr = "PP";
|
||||
break;
|
||||
return useDateFormat(dt, "YYYY-MM-DD (dddd)").value;
|
||||
case "short":
|
||||
formatStr = "P";
|
||||
break;
|
||||
return useDateFormat(dt, "YYYY-MM-DD").value;
|
||||
case "human":
|
||||
// January 1st, 2021
|
||||
return `${months[dt.getMonth()]} ${dt.getDate()}${ordinalIndicator(dt.getDate())}, ${dt.getFullYear()}`;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
if (type === "datetime") {
|
||||
formatStr += "p";
|
||||
}
|
||||
|
||||
return format(dt, formatStr, localeOptions);
|
||||
}
|
||||
|
||||
@@ -18,11 +18,7 @@ function connect(onmessage: (m: EventMessage) => void) {
|
||||
protocol = "wss";
|
||||
}
|
||||
|
||||
const dev = import.meta.dev;
|
||||
|
||||
const host = dev ? window.location.host.replace("3000", "7745") : window.location.host;
|
||||
|
||||
const ws = new WebSocket(`${protocol}://${host}/api/v1/ws/events`);
|
||||
const ws = new WebSocket(`${protocol}://${window.location.host}/api/v1/ws/events`);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.debug("connected to server");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<main class="grid min-h-screen w-full place-items-center">
|
||||
<main class="grid min-h-screen w-full place-items-center bg-blue-100">
|
||||
<slot></slot>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div>
|
||||
<!--
|
||||
Confirmation Modal is a singleton used by all components so we render
|
||||
it here to ensure it's always available. Possibly could move this further
|
||||
up the tree
|
||||
-->
|
||||
<ModalConfirm />
|
||||
<AppOutdatedModal v-model="modals.outdated" :current="current ?? ''" :latest="latest ?? ''" />
|
||||
<ItemCreateModal v-model="modals.item" />
|
||||
<LabelCreateModal v-model="modals.label" />
|
||||
<LocationCreateModal v-model="modals.location" />
|
||||
@@ -101,9 +100,10 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { lt } from "semver";
|
||||
import { useLabelStore } from "~~/stores/labels";
|
||||
import { useLocationStore } from "~~/stores/locations";
|
||||
import MdiMenu from "~icons/mdi/menu";
|
||||
import MdiPlus from "~icons/mdi/plus";
|
||||
|
||||
import MdiHome from "~icons/mdi/home";
|
||||
import MdiFileTree from "~icons/mdi/file-tree";
|
||||
@@ -111,8 +111,6 @@
|
||||
import MdiAccount from "~icons/mdi/account";
|
||||
import MdiCog from "~icons/mdi/cog";
|
||||
import MdiWrench from "~icons/mdi/wrench";
|
||||
import MdiMenu from "~icons/mdi/menu";
|
||||
import MdiPlus from "~icons/mdi/plus";
|
||||
|
||||
const { t } = useI18n();
|
||||
const username = computed(() => authCtx.user?.name || "User");
|
||||
@@ -126,15 +124,6 @@
|
||||
return data;
|
||||
});
|
||||
|
||||
const latest = computed(() => status.value?.latest.version);
|
||||
const current = computed(() => status.value?.build.version);
|
||||
|
||||
const isDev = computed(() => import.meta.dev || !current.value?.includes("."));
|
||||
const isOutdated = computed(() => current.value && latest.value && lt(current.value, latest.value));
|
||||
const hasHiddenLatest = computed(() => localStorage.getItem("latestVersion") === latest.value);
|
||||
|
||||
const displayOutdatedWarning = computed(() => !isDev && !hasHiddenLatest.value && isOutdated.value);
|
||||
|
||||
// Preload currency format
|
||||
useFormatCurrency();
|
||||
const modals = reactive({
|
||||
@@ -142,14 +131,6 @@
|
||||
location: false,
|
||||
label: false,
|
||||
import: false,
|
||||
outdated: displayOutdatedWarning.value,
|
||||
});
|
||||
|
||||
watch(displayOutdatedWarning, () => {
|
||||
console.log("displayOutdatedWarning", displayOutdatedWarning.value);
|
||||
if (displayOutdatedWarning.value) {
|
||||
modals.outdated = true;
|
||||
}
|
||||
});
|
||||
|
||||
const dropdown = [
|
||||
|
||||
@@ -191,72 +191,4 @@ describe("user should be able to create an item and add an attachment", () => {
|
||||
|
||||
cleanup();
|
||||
});
|
||||
|
||||
test("child items sync their location to their parent", async () => {
|
||||
const api = await sharedUserClient();
|
||||
const [parentLocation, parentCleanup] = await useLocation(api);
|
||||
const [childsLocation, childsCleanup] = await useLocation(api);
|
||||
|
||||
const { response: parentResponse, data: parent } = await api.items.create({
|
||||
name: "parent-item",
|
||||
labelIds: [],
|
||||
description: "test-description",
|
||||
locationId: parentLocation.id,
|
||||
});
|
||||
expect(parentResponse.status).toBe(201);
|
||||
expect(parent.id).toBeTruthy();
|
||||
|
||||
const { response: child1Response, data: child1Item } = await api.items.create({
|
||||
name: "child1-item",
|
||||
labelIds: [],
|
||||
description: "test-description",
|
||||
locationId: childsLocation.id,
|
||||
});
|
||||
expect(child1Response.status).toBe(201);
|
||||
const child1ItemUpdate = {
|
||||
parentId: parent.id,
|
||||
...child1Item,
|
||||
locationId: child1Item.location?.id,
|
||||
labelIds: [],
|
||||
};
|
||||
const { response: child1UpdatedResponse } = await api.items.update(child1Item.id, child1ItemUpdate as ItemUpdate);
|
||||
expect(child1UpdatedResponse.status).toBe(200);
|
||||
|
||||
const { response: child2Response, data: child2Item } = await api.items.create({
|
||||
name: "child2-item",
|
||||
labelIds: [],
|
||||
description: "test-description",
|
||||
locationId: childsLocation.id,
|
||||
});
|
||||
expect(child2Response.status).toBe(201);
|
||||
const child2ItemUpdate = {
|
||||
parentId: parent.id,
|
||||
...child2Item,
|
||||
locationId: child2Item.location?.id,
|
||||
labelIds: [],
|
||||
};
|
||||
const { response: child2UpdatedResponse } = await api.items.update(child2Item.id, child2ItemUpdate as ItemUpdate);
|
||||
expect(child2UpdatedResponse.status).toBe(200);
|
||||
|
||||
const itemUpdate = {
|
||||
parentId: null,
|
||||
...parent,
|
||||
locationId: parentLocation.id,
|
||||
labelIds: [],
|
||||
syncChildItemsLocations: true,
|
||||
};
|
||||
const { response: updateResponse } = await api.items.update(parent.id, itemUpdate);
|
||||
expect(updateResponse.status).toBe(200);
|
||||
|
||||
const { response: child1FinalResponse, data: child1FinalData } = await api.items.get(child1Item.id);
|
||||
expect(child1FinalResponse.status).toBe(200);
|
||||
expect(child1FinalData.location?.id).toBe(parentLocation.id);
|
||||
|
||||
const { response: child2FinalResponse, data: child2FinalData } = await api.items.get(child2Item.id);
|
||||
expect(child2FinalResponse.status).toBe(200);
|
||||
expect(child2FinalData.location?.id).toBe(parentLocation.id);
|
||||
|
||||
parentCleanup();
|
||||
childsCleanup();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -116,7 +116,6 @@ export interface ItemOut {
|
||||
/** Sold */
|
||||
soldTime: Date | string;
|
||||
soldTo: string;
|
||||
syncChildItemsLocations: boolean;
|
||||
updatedAt: Date | string;
|
||||
warrantyDetails: string;
|
||||
warrantyExpires: Date | string;
|
||||
@@ -135,8 +134,6 @@ export interface ItemPath {
|
||||
|
||||
export interface ItemSummary {
|
||||
archived: boolean;
|
||||
/** @example "0" */
|
||||
assetId: string;
|
||||
createdAt: Date | string;
|
||||
description: string;
|
||||
id: string;
|
||||
@@ -193,7 +190,6 @@ export interface ItemUpdate {
|
||||
soldTime: Date | string;
|
||||
/** @maxLength 255 */
|
||||
soldTo: string;
|
||||
syncChildItemsLocations: boolean;
|
||||
warrantyDetails: string;
|
||||
warrantyExpires: Date | string;
|
||||
}
|
||||
@@ -392,11 +388,6 @@ export interface ValueOverTimeEntry {
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface Latest {
|
||||
date: Date | string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface UserRegistration {
|
||||
email: string;
|
||||
name: string;
|
||||
@@ -409,7 +400,6 @@ export interface APISummary {
|
||||
build: Build;
|
||||
demo: boolean;
|
||||
health: boolean;
|
||||
latest: Latest;
|
||||
message: string;
|
||||
title: string;
|
||||
versions: string[];
|
||||
@@ -450,10 +440,8 @@ export interface ItemAttachmentToken {
|
||||
}
|
||||
|
||||
export interface LoginForm {
|
||||
/** @example "admin" */
|
||||
password: string;
|
||||
stayLoggedIn: boolean;
|
||||
/** @example "admin@admin.com" */
|
||||
username: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,19 +25,13 @@ describe("zeroTime", () => {
|
||||
describe("factorRange", () => {
|
||||
test("should return a range of dates", () => {
|
||||
const [start, end] = factorRange(10);
|
||||
|
||||
// Start should be today
|
||||
expect(start).toBeInstanceOf(Date);
|
||||
expect(start.getFullYear()).toBe(new Date().getFullYear());
|
||||
|
||||
// End should be 10 days from now
|
||||
expect(end).toBeInstanceOf(Date);
|
||||
|
||||
// Set the future date so it works even in late December when the year changes
|
||||
const futureDate = new Date();
|
||||
futureDate.setDate(futureDate.getDate() + 10); // Adds 10 days to the current date
|
||||
|
||||
expect(end.getFullYear()).toBe(futureDate.getFullYear());
|
||||
expect(end.getFullYear()).toBe(new Date().getFullYear());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -11,9 +11,7 @@ export function format(date: Date | string): string {
|
||||
}
|
||||
|
||||
export function zeroTime(date: Date): Date {
|
||||
return new Date(
|
||||
new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - date.getTimezoneOffset() * 60000
|
||||
);
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
}
|
||||
|
||||
export function factorRange(offset: number = 7): [Date, Date] {
|
||||
|
||||
56
frontend/lib/strings/index.test.ts
Normal file
56
frontend/lib/strings/index.test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { describe, test, expect } from "vitest";
|
||||
import { titlecase, capitalize, truncate } from ".";
|
||||
|
||||
describe("title case tests", () => {
|
||||
test("should return the same string if it's already title case", () => {
|
||||
expect(titlecase("Hello World")).toBe("Hello World");
|
||||
});
|
||||
|
||||
test("should title case a lower case word", () => {
|
||||
expect(titlecase("hello")).toBe("Hello");
|
||||
});
|
||||
|
||||
test("should title case a sentence", () => {
|
||||
expect(titlecase("hello world")).toBe("Hello World");
|
||||
});
|
||||
|
||||
test("should title case a sentence with multiple words", () => {
|
||||
expect(titlecase("hello world this is a test")).toBe("Hello World This Is A Test");
|
||||
});
|
||||
});
|
||||
|
||||
describe("capitilize tests", () => {
|
||||
test("should return the same string if it's already capitalized", () => {
|
||||
expect(capitalize("Hello")).toBe("Hello");
|
||||
});
|
||||
|
||||
test("should capitalize a lower case word", () => {
|
||||
expect(capitalize("hello")).toBe("Hello");
|
||||
});
|
||||
|
||||
test("should capitalize a sentence", () => {
|
||||
expect(capitalize("hello world")).toBe("Hello world");
|
||||
});
|
||||
|
||||
test("should capitalize a sentence with multiple words", () => {
|
||||
expect(capitalize("hello world this is a test")).toBe("Hello world this is a test");
|
||||
});
|
||||
});
|
||||
|
||||
describe("truncase tests", () => {
|
||||
test("should return the same string if it's already truncated", () => {
|
||||
expect(truncate("Hello", 5)).toBe("Hello");
|
||||
});
|
||||
|
||||
test("should truncate a lower case word", () => {
|
||||
expect(truncate("hello", 3)).toBe("hel...");
|
||||
});
|
||||
|
||||
test("should truncate a sentence", () => {
|
||||
expect(truncate("hello world", 5)).toBe("hello...");
|
||||
});
|
||||
|
||||
test("should truncate a sentence with multiple words", () => {
|
||||
expect(truncate("hello world this is a test", 10)).toBe("hello worl...");
|
||||
});
|
||||
});
|
||||
14
frontend/lib/strings/index.ts
Normal file
14
frontend/lib/strings/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export function titlecase(str: string) {
|
||||
return str
|
||||
.split(" ")
|
||||
.map(word => word[0].toUpperCase() + word.slice(1))
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
export function capitalize(str: string) {
|
||||
return str[0].toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
export function truncate(str: string, length: number) {
|
||||
return str.length > length ? str.substring(0, length) + "..." : str;
|
||||
}
|
||||
@@ -9,30 +9,6 @@
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "fa {0}",
|
||||
"days": "dies",
|
||||
"hour": "hora",
|
||||
"hours": "hores",
|
||||
"in": "a {0}",
|
||||
"just-now": "ara mateix",
|
||||
"last-month": "el mes passat",
|
||||
"last-week": "la setmana passada",
|
||||
"last-year": "darrer any",
|
||||
"minute": "minut",
|
||||
"minutes": "minuts",
|
||||
"months": "mesos",
|
||||
"next-month": "Mes següent",
|
||||
"next-week": "la setmana vinent",
|
||||
"next-year": "Any següent",
|
||||
"second": "segon",
|
||||
"seconds": "segons",
|
||||
"tomorrow": "demà",
|
||||
"week": "setmana",
|
||||
"weeks": "setmanes",
|
||||
"years": "anys",
|
||||
"yesterday": "ahir"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "URL de la pàgina"
|
||||
},
|
||||
@@ -42,8 +18,6 @@
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Descripció de l'article",
|
||||
"item_name": "Nom de l'article",
|
||||
"photo_button": "Foto 📷",
|
||||
"title": "Crea un article"
|
||||
},
|
||||
@@ -53,45 +27,26 @@
|
||||
"items": "Articles",
|
||||
"no_items": "No hi ha articles a mostrar",
|
||||
"table": "Taula"
|
||||
},
|
||||
"table": {
|
||||
"page": "Pàgina",
|
||||
"rows_per_page": "Files per pàgina"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Descripció de l'etiqueta",
|
||||
"label_name": "Nom de l'etiqueta",
|
||||
"title": "Crea una etiqueta"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Descripció de la ubicació",
|
||||
"location_name": "Nom de la ubicació",
|
||||
"title": "Crea una ubicació"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Ubicació pare"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "No hi ha ubicacions disponibles. Afegiu ubicacions amb el botó\n `<`span class=\"link-primary\"`>`Crea`<`/span`>` a la barra de navegació."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Afegeix",
|
||||
"build": "Construcció: { build }",
|
||||
"confirm": "Confirma",
|
||||
"create": "Crea",
|
||||
"create_and_add": "Crea i afegeix-ne un altre",
|
||||
"created": "Creat",
|
||||
"delete": "Esborra",
|
||||
"details": "Detalls",
|
||||
"duplicate": "Duplica",
|
||||
"edit": "Edita",
|
||||
"email": "Correu electrònic",
|
||||
"follow_dev": "Segueix al desenvolupador",
|
||||
"github": "Projecte de GitHub",
|
||||
@@ -99,29 +54,15 @@
|
||||
"join_discord": "Uniu-vos a Discord",
|
||||
"labels": "Etiquetes",
|
||||
"locations": "Ubicacions",
|
||||
"maintenance": "Manteniment",
|
||||
"name": "Nom",
|
||||
"password": "Contrasenya",
|
||||
"read_docs": "Llegiu la documentació",
|
||||
"save": "Desa",
|
||||
"search": "Cerca",
|
||||
"sign_out": "Tanca la sessió",
|
||||
"submit": "Envia",
|
||||
"update": "Actualitza",
|
||||
"value": "Valor",
|
||||
"version": "Versió {version}",
|
||||
"welcome": "Us donem la benvinguda, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Etiquetes",
|
||||
"quick_statistics": "Estadístiques ràpides",
|
||||
"recently_added": "Afegit recentment",
|
||||
"storage_locations": "Ubicacions d'emmagatzematge",
|
||||
"total_items": "Articles totals",
|
||||
"total_labels": "Total d'etiquetes",
|
||||
"total_locations": "Ubicacions totals",
|
||||
"total_value": "Valor total"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "El registre és desactivat",
|
||||
"dont_join_group": "Voleu unir-vos al grup?",
|
||||
@@ -136,71 +77,32 @@
|
||||
},
|
||||
"items": {
|
||||
"add": "Afegeix",
|
||||
"advanced": "Mode avançat",
|
||||
"archived": "Arxivat",
|
||||
"asset_id": "ID de l'actiu",
|
||||
"attachment": "Adjunt",
|
||||
"attachments": "Documents adjunts",
|
||||
"changes_persisted_immediately": "Els canvis als fitxers adjunts es desaran immediatament",
|
||||
"created_at": "Creat a",
|
||||
"custom_fields": "Camps personalitzats",
|
||||
"description": "Descripció",
|
||||
"details": "Detalls",
|
||||
"drag_and_drop": "Arrossegueu i deixeu anar fitxers aquí o feu clic per seleccionar fitxers",
|
||||
"edit_details": "Edita els detalls",
|
||||
"field_selector": "Selector del camp",
|
||||
"field_value": "Valor del camp",
|
||||
"first": "Primer",
|
||||
"include_archive": "Inclou els articles arxivats",
|
||||
"insured": "Assegurat",
|
||||
"last": "Últim",
|
||||
"lifetime_warranty": "Garantia de per vida",
|
||||
"location": "Ubicació",
|
||||
"manual": "Manual",
|
||||
"manuals": "Manuals",
|
||||
"manufacturer": "Fabricant",
|
||||
"model_number": "Número de model",
|
||||
"name": "Nom",
|
||||
"negate_labels": "Nega les etiquetes seleccionades",
|
||||
"next_page": "Pàgina següent",
|
||||
"no_results": "No s'ha trobat cap element",
|
||||
"notes": "Notes",
|
||||
"options": "Opcions",
|
||||
"order_by": "Ordena per",
|
||||
"pages": "Pàgina { page } de { totalPages }",
|
||||
"parent_item": "Article pare",
|
||||
"photo": "Foto",
|
||||
"photos": "Fotos",
|
||||
"prev_page": "Pàgina anterior",
|
||||
"purchase_date": "Data de compra",
|
||||
"purchase_details": "Detalls de la compra",
|
||||
"purchase_price": "Preu de compra",
|
||||
"purchased_from": "Comprat a",
|
||||
"quantity": "Quantitat",
|
||||
"query_id": "S'està consultant el número d'identificació de l'actiu: { id }",
|
||||
"receipt": "Tiquet",
|
||||
"receipts": "Factures",
|
||||
"reset_search": "Reinicia la cerca",
|
||||
"results": "{ total } resultats",
|
||||
"serial_number": "Número de sèrie",
|
||||
"show_advanced_view_options": "Mostra les opcions avançades de visualització",
|
||||
"sold_at": "Venut a (lloc)",
|
||||
"sold_details": "Detalls de la venda",
|
||||
"sold_price": "Preu de venda",
|
||||
"sold_to": "Venut a",
|
||||
"tip_1": "Els filtres d'ubicació i etiquetes utilitzen l'operació «O». Si se'n selecciona més d'un, \nnomés se'n requerirà un per a coincidència.",
|
||||
"tip_2": "Les cerques amb el prefix «#» sol·licitaran un ID d'un actiu (per exemple, «#000-001»)",
|
||||
"tip_3": "Els filtres de camp utilitzen l'operació «O». Si se'n selecciona més d'un, \nnomés se'n requerirà un per a coincidència.",
|
||||
"tips": "Consells",
|
||||
"tips_sub": "Consells de cerca",
|
||||
"updated_at": "Actualitzat a",
|
||||
"warranty": "Garantia",
|
||||
"warranty_details": "Detalls de la garantia",
|
||||
"warranty_expires": "La garantia caduca"
|
||||
"updated_at": "Actualitzat a"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "No s'han trobat etiquetes",
|
||||
"update_label": "Actualitza l'etiqueta"
|
||||
"no_results": "No s'han trobat etiquetes"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Català",
|
||||
@@ -210,70 +112,29 @@
|
||||
"fr": "Francès",
|
||||
"hu": "Hongarès",
|
||||
"it": "Italià",
|
||||
"ja-JP": "Japonès",
|
||||
"nl": "Neerlandès",
|
||||
"pl": "Polonès",
|
||||
"pt-BR": "Portuguès (Brasil)",
|
||||
"pt-PT": "Portuguès (Portugal)",
|
||||
"ru": "Rus",
|
||||
"sl": "Eslovè",
|
||||
"sv": "Suec",
|
||||
"tr": "Turc",
|
||||
"uk-UA": "Ucraïnès",
|
||||
"zh-CN": "Xinès (simplificat)",
|
||||
"zh-HK": "Xinès (Hong Kong)",
|
||||
"zh-MO": "Xinès (Macau)",
|
||||
"zh-TW": "Xinès (tradicional)"
|
||||
},
|
||||
"languages.da-DK": "Danès",
|
||||
"languages.fi.FI": "Finès",
|
||||
"languages.ro-RO": "Romanès",
|
||||
"languages.sk-SK": "Eslovac",
|
||||
"locations": {
|
||||
"child_locations": "Ubicacions infantils",
|
||||
"collapse_tree": "Col·lapsa l'arbre",
|
||||
"no_results": "No s'han trobat ubicacions",
|
||||
"update_location": "Actualitza ubicació"
|
||||
"no_results": "No s'han trobat ubicacions"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "Ambdós",
|
||||
"completed": "Acabat",
|
||||
"scheduled": "Programat"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Acabar",
|
||||
"create_first": "Creeu la vostra primera entrada",
|
||||
"delete": "Esborra",
|
||||
"duplicate": "Duplica",
|
||||
"edit": "Edita",
|
||||
"new": "Nou"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Data de finalització",
|
||||
"cost": "Preu",
|
||||
"delete_confirmation": "Esteu segur que voleu suprimir aquest registre?",
|
||||
"edit_action": "Actualitza",
|
||||
"edit_title": "Edita l'entrada",
|
||||
"entry_name": "Nom de l'entrada",
|
||||
"new_action": "Crea",
|
||||
"new_title": "Nova entrada",
|
||||
"notes": "Notes",
|
||||
"scheduled_date": "Data programada"
|
||||
},
|
||||
"monthly_average": "Mitjana mensual",
|
||||
"toast": {
|
||||
"failed_to_create": "No s'ha pogut crear l'entrada",
|
||||
"failed_to_delete": "No s'ha pogut suprimir l'entrada",
|
||||
"failed_to_update": "No s'ha pogut actualitzar l'entrada"
|
||||
"both": "Ambdós"
|
||||
},
|
||||
"total_cost": "Cost total",
|
||||
"total_entries": "Nombre d'entrades"
|
||||
"total_entries": "Nombre d' entrades"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Article / Actiu",
|
||||
"create_label": "Etiqueta",
|
||||
"create_location": "Ubicació",
|
||||
"home": "Inici",
|
||||
"locations": "Ubicacions",
|
||||
"maintenance": "Manteniment",
|
||||
@@ -290,7 +151,6 @@
|
||||
"delete_account_sub": "Elimina el compte i totes les dades associades. Aquesta acció no es pot desfer.",
|
||||
"display_header": "{ currentValue, select, true {Amaga la capçalera} false {Mostra la capçalera} other {Desconegut}}",
|
||||
"enabled": "Habilitat",
|
||||
"example": "Exemple",
|
||||
"gen_invite": "Genera un enllaç d'invitació",
|
||||
"group_settings": "Configuració del grup",
|
||||
"group_settings_sub": "Configuració del grup compartit. És possible que hàgiu d'actualitzar la pàgina per aplicar la configuració.",
|
||||
@@ -315,27 +175,8 @@
|
||||
"actions_set": {
|
||||
"ensure_ids": "Assegura els identificadors de recursos",
|
||||
"ensure_ids_button": "Assegura els identificadors de recursos",
|
||||
"ensure_import_refs": "Assegureu-vos d'importar les referències",
|
||||
"ensure_import_refs_button": "Assegureu-vos d'importar les referències",
|
||||
"set_primary_photo": "Defineix la foto principal",
|
||||
"set_primary_photo_button": "Defineix la foto principal"
|
||||
},
|
||||
"import_export": "Importa / Exporta",
|
||||
"import_export_set": {
|
||||
"export": "Exporta inventari",
|
||||
"export_button": "Exporta inventari",
|
||||
"export_sub": "Exporta el format CSV estàndard per a Homebox. S'exportaran tots els articles de l'inventari.",
|
||||
"import": "Importa inventari",
|
||||
"import_button": "Importa inventari"
|
||||
},
|
||||
"import_export_sub": "Importa i exporta l'inventari amb un fitxer CSV. És útil per a migracions d'inventari a una nova instància de Homebox.",
|
||||
"reports": "Informes",
|
||||
"reports_set": {
|
||||
"asset_labels": "Etiquetes d'identificador de recurs",
|
||||
"asset_labels_button": "Generador d'etiquetes",
|
||||
"bill_of_materials": "Llista de materials",
|
||||
"bill_of_materials_button": "Genera llista de materials"
|
||||
},
|
||||
"reports_sub": "Genera informes per a l'inventari"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,287 +0,0 @@
|
||||
{
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"description": "Importujte CSV soubor obashující vaše položky, štítky a lokace. Pro dodatečné informace o formátu použijte \ndokumentaci.",
|
||||
"title": "Importovat CSV Soubor",
|
||||
"upload": "Nahrát"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "Před {0}",
|
||||
"days": "dny",
|
||||
"hour": "Hodina",
|
||||
"hours": "Hodinami",
|
||||
"in": "za {0}",
|
||||
"just-now": "Právě teď",
|
||||
"last-month": "Minulý měsíc",
|
||||
"last-week": "Minulý týden",
|
||||
"last-year": "Minulý rok",
|
||||
"minute": "minuta",
|
||||
"minutes": "minutami",
|
||||
"months": "měsíci",
|
||||
"next-month": "Přiští měsíc",
|
||||
"next-week": "příští týden",
|
||||
"next-year": "příští rok",
|
||||
"second": "sekunda",
|
||||
"seconds": "sekundami",
|
||||
"tomorrow": "zítra",
|
||||
"week": "týden",
|
||||
"weeks": "týdny",
|
||||
"years": "roky",
|
||||
"yesterday": "včera"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "URL Stránky"
|
||||
},
|
||||
"password_score": {
|
||||
"password_strength": "Síla Hesla"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Popis Položky",
|
||||
"item_name": "Jméno Položky",
|
||||
"photo_button": "Fotka 📷",
|
||||
"title": "Vytvořit položku"
|
||||
},
|
||||
"view": {
|
||||
"selectable": {
|
||||
"card": "Karta",
|
||||
"items": "Položky",
|
||||
"no_items": "Žádné položky k zobrazení",
|
||||
"table": "Tabulka"
|
||||
},
|
||||
"table": {
|
||||
"page": "Stránka",
|
||||
"rows_per_page": "Řádků na stránku"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Popis Popisku",
|
||||
"label_name": "Název Popisku",
|
||||
"title": "Vytvořit popisek"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Popis lokace",
|
||||
"location_name": "Název Lokace",
|
||||
"title": "Vytvořit Lokaci"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Nadřazená Lokace"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Nejsou dostupné žádné lokace. Přidejte nové lokace\npomocí talčítka `<`span class=\"link-primary\"`>`Vytvořit`<`/span`>` na navigační liště."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Přidat",
|
||||
"build": "Sestavení: { build }",
|
||||
"confirm": "Potvrdit",
|
||||
"create": "Vytvořit",
|
||||
"create_and_add": "Vytvořit a Přidat Další",
|
||||
"created": "Vytvořeno",
|
||||
"delete": "Smazat",
|
||||
"details": "Detaily",
|
||||
"duplicate": "Duplikovat",
|
||||
"edit": "Upravit",
|
||||
"email": "Email",
|
||||
"follow_dev": "Sledovat vývojáře",
|
||||
"github": "GitHub Projekt",
|
||||
"items": "Položky",
|
||||
"join_discord": "Připojte se na Discors",
|
||||
"labels": "Popisky",
|
||||
"locations": "Lokace",
|
||||
"maintenance": "Údržba",
|
||||
"name": "Jméno",
|
||||
"password": "Heslo",
|
||||
"read_docs": "Přečtěte si Dokumentaci",
|
||||
"save": "Uložit",
|
||||
"search": "Vyhledávat",
|
||||
"sign_out": "Odhlásit se",
|
||||
"submit": "Potvrdit",
|
||||
"update": "Aktualizovat",
|
||||
"value": "Hodnota",
|
||||
"version": "Verze: { version }",
|
||||
"welcome": "Vítejte, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Popisky",
|
||||
"quick_statistics": "Rychlé informace",
|
||||
"recently_added": "Nedávno přidané",
|
||||
"storage_locations": "Úložné lokace",
|
||||
"total_items": "Celkových Položek",
|
||||
"total_labels": "Celkových popisků",
|
||||
"total_locations": "Celkových lokací",
|
||||
"total_value": "Celková hodnota"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Registrace je Zakázána",
|
||||
"dont_join_group": "Nechcete se přidat do skupiny?",
|
||||
"joining_group": "Přidáváte se do existující skupiny!",
|
||||
"login": "Přihlásit se",
|
||||
"register": "Registrovat se",
|
||||
"remember_me": "Zapamatovat si mě",
|
||||
"set_email": "Jaký je váš email?",
|
||||
"set_name": "Jak se jmenujete?",
|
||||
"set_password": "Nastavte si heslo"
|
||||
},
|
||||
"items": {
|
||||
"add": "Přidat",
|
||||
"advanced": "Pokročilé",
|
||||
"archived": "Archivované",
|
||||
"asset_id": "ID Položky",
|
||||
"attachment": "Přiloha",
|
||||
"attachments": "Přilohy",
|
||||
"changes_persisted_immediately": "Změny v přílohách budou uloženy okamžitě",
|
||||
"created_at": "Vytvořeno",
|
||||
"custom_fields": "Vlastní Data",
|
||||
"description": "Popis",
|
||||
"details": "Detaily",
|
||||
"drag_and_drop": "Přetáhněte sem soubory nebo klikněte pro výběr",
|
||||
"edit_details": "Upravit Detaily",
|
||||
"field_selector": "Výběř Pole",
|
||||
"field_value": "Hodnota Pole",
|
||||
"first": "První",
|
||||
"include_archive": "Zahrnout i archivované Položky",
|
||||
"insured": "Pojištěné",
|
||||
"last": "Poslední",
|
||||
"lifetime_warranty": "Doživotní záruka",
|
||||
"location": "Lokace",
|
||||
"manual": "Návod",
|
||||
"manuals": "Návody",
|
||||
"manufacturer": "Výrobce",
|
||||
"model_number": "Číslo Modelu",
|
||||
"name": "Jméno",
|
||||
"negate_labels": "Prohodit Vybrané Popisky",
|
||||
"next_page": "Další Stránka",
|
||||
"no_results": "Nebyly nalezeny žádné Položky",
|
||||
"notes": "Poznámky",
|
||||
"options": "Možnosti",
|
||||
"order_by": "Seřadit Podle",
|
||||
"pages": "Stránka { page } z { totalPages }",
|
||||
"parent_item": "Nadřazená Položka",
|
||||
"photo": "Fotka",
|
||||
"photos": "Fotky",
|
||||
"prev_page": "Předešlá strana",
|
||||
"purchase_date": "Datum Nákupu",
|
||||
"purchase_details": "Detaily Nákupu",
|
||||
"purchase_price": "Nákupní cena",
|
||||
"purchased_from": "Koupeno Od",
|
||||
"quantity": "Množství",
|
||||
"receipt": "Účtenka",
|
||||
"receipts": "Účtenky",
|
||||
"reset_search": "Obnovit Vyhledávání",
|
||||
"results": "{ total } Výsledků",
|
||||
"serial_number": "Seriové číslo",
|
||||
"show_advanced_view_options": "Zobrazit Pokročilé Možnosti Zobrazení",
|
||||
"sold_at": "Prodáno",
|
||||
"sold_details": "Detaily Prodeje",
|
||||
"sold_price": "Cena Prodeje",
|
||||
"sold_to": "Prodáno Komu",
|
||||
"tips": "Návrhy",
|
||||
"tips_sub": "Vyhledat Návrhy",
|
||||
"updated_at": "Aktualizováno",
|
||||
"warranty": "Záruka",
|
||||
"warranty_details": "Detaily Záruky",
|
||||
"warranty_expires": "Expirace Záruky"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Žádné Popisky nebyly nalezeny",
|
||||
"update_label": "Aktualizovat Popisek"
|
||||
},
|
||||
"languages": {
|
||||
"de": "Němčina",
|
||||
"en": "Angličtina",
|
||||
"es": "Španělština",
|
||||
"fr": "Francouzština",
|
||||
"hu": "Maďarština",
|
||||
"it": "Italština",
|
||||
"ja-JP": "Japonština",
|
||||
"pl": "Polština",
|
||||
"pt-BR": "Portugalština (Brazílie)",
|
||||
"pt-PT": "Portugalština (Portugalsko)",
|
||||
"ru": "Ruština",
|
||||
"sl": "Slovinština",
|
||||
"sv": "Švédština",
|
||||
"uk-UA": "Ukrajinština",
|
||||
"zh-CN": "Čínština (Zjednodušená)",
|
||||
"zh-HK": "Čínština (Hong Kong)",
|
||||
"zh-MO": "Čínština (Macau)",
|
||||
"zh-TW": "Čínština (Tradiční)"
|
||||
},
|
||||
"languages.da-DK": "Dánština",
|
||||
"languages.fi.FI": "Finština",
|
||||
"languages.sk-SK": "Slovenština",
|
||||
"locations": {
|
||||
"child_locations": "Podřazené Lokace",
|
||||
"collapse_tree": "Zabalit Strom",
|
||||
"no_results": "Žádné lokace nebyly nalezeny",
|
||||
"update_location": "Aktualizovat Lokaci"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "Obojí",
|
||||
"completed": "Hotové"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Hotovo",
|
||||
"create_first": "Vytvořte první záznam",
|
||||
"delete": "Smazat",
|
||||
"duplicate": "Duplikovat",
|
||||
"edit": "Upravit",
|
||||
"new": "Nové"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Datum Dokončení",
|
||||
"cost": "Nákaldy",
|
||||
"delete_confirmation": "Jste si jistí že chcete tento záznam smazat?",
|
||||
"edit_action": "Aktualizovat",
|
||||
"edit_title": "Upravit Záznam",
|
||||
"entry_name": "Název Záznamu",
|
||||
"new_action": "Vytvořit",
|
||||
"new_title": "Nový Záznam",
|
||||
"notes": "Poznámky"
|
||||
},
|
||||
"monthly_average": "Průměr za měsíc",
|
||||
"toast": {
|
||||
"failed_to_create": "Vytváření záznamu selhalo",
|
||||
"failed_to_delete": "Mazání záznamu selhalo",
|
||||
"failed_to_update": "Úprava záznamu selhala"
|
||||
},
|
||||
"total_cost": "Celkové náklady",
|
||||
"total_entries": "Počet záznamů"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Položka",
|
||||
"create_label": "Popisek",
|
||||
"create_location": "Lokace",
|
||||
"home": "Domů",
|
||||
"locations": "Lokace",
|
||||
"profile": "Profil",
|
||||
"search": "Vyhledávání",
|
||||
"tools": "Nástroje"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Aktivní",
|
||||
"change_password": "Změnit Heslo",
|
||||
"currency_format": "Měnový Formát",
|
||||
"current_password": "Aktuální Heslo",
|
||||
"delete_account": "Smazat Účet",
|
||||
"delete_account_sub": "Smaže se vás účet a všechny s ním spojená data. Z této akce se nelze navrátit.",
|
||||
"enabled": "Povoleno",
|
||||
"example": "Příklad",
|
||||
"gen_invite": "Vytvořit zvací odkaz",
|
||||
"group_settings": "Nastavení Skupiny",
|
||||
"inactive": "Neaktivní",
|
||||
"language": "Jazyk",
|
||||
"new_password": "Nové Heslo",
|
||||
"test": "Zkouška"
|
||||
}
|
||||
}
|
||||
@@ -1,49 +1,12 @@
|
||||
{
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Adfærd for imports med eksisterende import_refs har ændret sig. Hvis en import_ref er tilstede i CSV filen,\nvil genstanden blive opdateret med værdierne fra CSV filen.",
|
||||
"description": "Importer en CSV fil som indeholder dine genstande, etiketter, og lokationer. Se dokumentation for mere information vedrørende\nden korrekte format.",
|
||||
"title": "Importer CSV Fil",
|
||||
"upload": "Upload"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "{0} siden",
|
||||
"days": "dage",
|
||||
"hour": "time",
|
||||
"hours": "timer",
|
||||
"in": "om {0}",
|
||||
"just-now": "lige nu",
|
||||
"last-month": "sidste måned",
|
||||
"last-week": "sidste uge",
|
||||
"last-year": "sidste år",
|
||||
"minute": "minut",
|
||||
"minutes": "minutter",
|
||||
"months": "måneder",
|
||||
"next-month": "næste måned",
|
||||
"next-week": "næste uge",
|
||||
"next-year": "næste år",
|
||||
"second": "sekund",
|
||||
"seconds": "sekunder",
|
||||
"tomorrow": "i morgen",
|
||||
"week": "uge",
|
||||
"weeks": "uger",
|
||||
"years": "år",
|
||||
"yesterday": "i går"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "Side URL"
|
||||
},
|
||||
"password_score": {
|
||||
"password_strength": "Adgangskodestyrke"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Genstandsbeskrivelse",
|
||||
"item_name": "Genstandsnavn",
|
||||
"photo_button": "Foto 📷",
|
||||
"title": "Opret genstand"
|
||||
},
|
||||
@@ -53,299 +16,37 @@
|
||||
"items": "Genstande",
|
||||
"no_items": "Ingen genstande at vise",
|
||||
"table": "Tabel"
|
||||
},
|
||||
"table": {
|
||||
"page": "Side",
|
||||
"rows_per_page": "Rækker per side"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Etiketbeskrivelse",
|
||||
"label_name": "Etiketnavn",
|
||||
"title": "Opret label"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Lokationsbeskrivelse",
|
||||
"location_name": "Lokationsnavn",
|
||||
"title": "Opret lokation"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Forældrelokation"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Ingen tilgængelige lokationer. Opret nye lokationer gennem\n`<`span class=\"link-primary\">`Opret`<`/span`>` knappen i navigationslinjen."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Tilføj",
|
||||
"build": "Build: { build }",
|
||||
"confirm": "Bekræft",
|
||||
"create": "Opret",
|
||||
"create_and_add": "Opret og tilføj ny",
|
||||
"created": "Oprettet",
|
||||
"delete": "Slet",
|
||||
"details": "Detaljer",
|
||||
"duplicate": "Dupliker",
|
||||
"edit": "Rediger",
|
||||
"email": "Email",
|
||||
"follow_dev": "Følg udvikleren",
|
||||
"github": "GitHub projekt",
|
||||
"items": "Genstande",
|
||||
"join_discord": "Deltag i vores Discord",
|
||||
"labels": "Etiketter",
|
||||
"locations": "Lokationer",
|
||||
"maintenance": "Opretholdelse",
|
||||
"name": "Navn",
|
||||
"password": "Adgangskode",
|
||||
"read_docs": "Læs Docs",
|
||||
"save": "Gem",
|
||||
"search": "Søg",
|
||||
"sign_out": "Log ud",
|
||||
"submit": "Indsend",
|
||||
"update": "Opdater",
|
||||
"value": "Værdi",
|
||||
"version": "Version: { version }",
|
||||
"welcome": "Velkommen, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Etiketter",
|
||||
"quick_statistics": "Hurtige Statistikker",
|
||||
"recently_added": "Nyligt Tilføjet",
|
||||
"storage_locations": "Opbevaringslokationer",
|
||||
"total_items": "Totale Genstande",
|
||||
"total_labels": "Totale Etiketter",
|
||||
"total_locations": "Totale Lokationer",
|
||||
"total_value": "Total Værdi"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Registrering slået fra",
|
||||
"dont_join_group": "Ikke lyst til at deltage i en gruppe?",
|
||||
"joining_group": "Du deltager i en eksisterende gruppe!",
|
||||
"login": "Log ind",
|
||||
"register": "Registrer",
|
||||
"remember_me": "Husk mig",
|
||||
"set_email": "Hvad er din E-Mail?",
|
||||
"set_name": "Hvad hedder du?",
|
||||
"set_password": "Opret din adgangskode",
|
||||
"tagline": "Følg, Organiser, og Håndter dine Ting."
|
||||
},
|
||||
"items": {
|
||||
"add": "Tilføj",
|
||||
"advanced": "Avanceret",
|
||||
"archived": "Arkiveret",
|
||||
"asset_id": "Aktiv-id",
|
||||
"attachment": "Vedhæftning",
|
||||
"attachments": "Vedhæftninger",
|
||||
"changes_persisted_immediately": "Ændringer af vedhæftede filer gemmes med det samme",
|
||||
"created_at": "Oprettet den",
|
||||
"custom_fields": "Brugerdefinerede felter",
|
||||
"description": "Beskrivelse",
|
||||
"details": "Detaljer",
|
||||
"drag_and_drop": "Træk og slip filer her, eller klik for at vælge filer",
|
||||
"edit_details": "Rediger detaljer",
|
||||
"field_selector": "Feltvælger",
|
||||
"field_value": "Feltværdi",
|
||||
"first": "Første",
|
||||
"include_archive": "Medtag arkiverede elementer",
|
||||
"insured": "Forsikret",
|
||||
"last": "Sidst",
|
||||
"lifetime_warranty": "livstidsgaranti",
|
||||
"location": "Lokalitet",
|
||||
"manual": "Manuel",
|
||||
"manuals": "Manualer",
|
||||
"manufacturer": "Producent",
|
||||
"model_number": "Modelnummer",
|
||||
"name": "Navn",
|
||||
"negate_labels": "Ophæv valgte etiketter",
|
||||
"next_page": "Næste side",
|
||||
"no_results": "Ingen elementer fundet",
|
||||
"notes": "Noter",
|
||||
"options": "Indstillinger",
|
||||
"order_by": "Sorter efter",
|
||||
"pages": "Side { page } af { totalPages }",
|
||||
"parent_item": "Overordnet element",
|
||||
"photo": "Foto",
|
||||
"photos": "Fotos",
|
||||
"prev_page": "Forrige side",
|
||||
"purchase_date": "Indkøbs dato",
|
||||
"purchase_details": "Købs detaljer",
|
||||
"purchase_price": "Indkøbspris",
|
||||
"purchased_from": "Købt fra",
|
||||
"quantity": "Antal",
|
||||
"query_id": "Forespørgsler på aktiv-id-nummer: { id }",
|
||||
"receipt": "Kvittering",
|
||||
"receipts": "Kvitteringer",
|
||||
"reset_search": "Nulstil Søgning",
|
||||
"results": "Samlede resultater",
|
||||
"serial_number": "Serienummer",
|
||||
"show_advanced_view_options": "vis avancerede indstillinger",
|
||||
"sold_at": "Solgt D.",
|
||||
"sold_details": "Salgs detaljer",
|
||||
"sold_price": "Solgt pris",
|
||||
"sold_to": "Sold til",
|
||||
"tip_1": "Placerings- og etiketfiltre bruger betjeningen 'ELLER'. Hvis mere end én er valgt, kræves der kun én\n til et match.",
|
||||
"tip_2": "Søgninger med præfikset '#'' vil forespørge efter et aktiv-id (eksempel '#000-001')",
|
||||
"tip_3": "Feltfiltre bruger handlingen 'ELLER'. Hvis mere end én er valgt, kræves der kun én til en\n kamp.",
|
||||
"tips": "Tips",
|
||||
"tips_sub": "Søgetips",
|
||||
"updated_at": "Opdateret d.",
|
||||
"warranty": "Garanti",
|
||||
"warranty_details": "Oplysninger om garanti",
|
||||
"warranty_expires": "Garantien udløber"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Ingen etiketter fundet",
|
||||
"update_label": "Opdater etiket"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Catalansk",
|
||||
"de": "Tysk",
|
||||
"en": "Engelsk",
|
||||
"es": "Spansk",
|
||||
"fr": "Fransk",
|
||||
"hu": "Ungarsk",
|
||||
"it": "Italiensk",
|
||||
"ja-JP": "Japansk",
|
||||
"nl": "Hollandsk",
|
||||
"pl": "Polsk",
|
||||
"pt-BR": "Portugisisk (Brasilien)",
|
||||
"pt-PT": "Portugisisk (Portugal)",
|
||||
"ru": "Russisk",
|
||||
"sl": "Slovensk",
|
||||
"sv": "Svensk",
|
||||
"tr": "Tyrkisk",
|
||||
"uk-UA": "Ukrainsk",
|
||||
"zh-CN": "Kinesisk (simplificeret)",
|
||||
"zh-HK": "Kinesisk (Hong Kong)",
|
||||
"zh-MO": "Kinesisk (Macao)",
|
||||
"zh-TW": "Kinesisk (Traditionel)"
|
||||
},
|
||||
"languages.da-DK": "Dansk",
|
||||
"languages.fi.FI": "Finsk",
|
||||
"languages.ro-RO": "Rumænsk",
|
||||
"languages.sk-SK": "Slovakisk",
|
||||
"locations": {
|
||||
"child_locations": "Underordnede placeringer",
|
||||
"collapse_tree": "Kollaps træ",
|
||||
"no_results": "Ingen placeringer fundet.",
|
||||
"update_location": "Opdatér sted"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "Begge",
|
||||
"completed": "Gennemført",
|
||||
"scheduled": "Planlagt"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Færdig",
|
||||
"create_first": "Opret din første post",
|
||||
"delete": "Slet",
|
||||
"duplicate": "Dupliker",
|
||||
"edit": "Rediger",
|
||||
"new": "Ny"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Gennemført den",
|
||||
"cost": "Omkostning",
|
||||
"delete_confirmation": "Er du sikker på at du vil slette denne indtastning?",
|
||||
"edit_action": "Opdater",
|
||||
"edit_title": "Rediger posten",
|
||||
"entry_name": "Postens navn",
|
||||
"new_action": "Opret",
|
||||
"new_title": "Ny indgang",
|
||||
"notes": "Noter",
|
||||
"scheduled_date": "Planlagt dato"
|
||||
},
|
||||
"monthly_average": "Månedligt gennemsnit",
|
||||
"toast": {
|
||||
"failed_to_create": "Kunne ikke oprette post",
|
||||
"failed_to_delete": "Kunne ikke slette post",
|
||||
"failed_to_update": "Kunne ikke opdatere posten"
|
||||
},
|
||||
"total_cost": "Samlede omkostninger",
|
||||
"total_entries": "Total antal poster"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Vare/aktiv",
|
||||
"create_label": "Label",
|
||||
"create_location": "Lokalitet",
|
||||
"home": "Hjem",
|
||||
"locations": "Lokationer",
|
||||
"maintenance": "Opretholdelse",
|
||||
"profile": "Profil",
|
||||
"search": "Søg",
|
||||
"tools": "Værktøjer"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Aktiv",
|
||||
"change_password": "Ændre adgangskode",
|
||||
"currency_format": "Valuta format",
|
||||
"current_password": "Aktuel adgangskode",
|
||||
"delete_account": "Slet Konto",
|
||||
"delete_account_sub": "Slet din konto og alle dens tilknyttede data",
|
||||
"display_header": "{ currentValue, select, true {Skjul header} false {Vis header} andet {Not Hit}}",
|
||||
"enabled": "Aktiveret",
|
||||
"example": "Eksempel",
|
||||
"gen_invite": "Generer invitationslink",
|
||||
"group_settings": "Gruppe indstillinger",
|
||||
"group_settings_sub": "Indstillinger for delt gruppe",
|
||||
"inactive": "Inaktiv",
|
||||
"language": "Sprog",
|
||||
"new_password": "Ny Adgangskode",
|
||||
"no_notifiers": "Ingen notifikationer konfiguret",
|
||||
"notifier_modal": "{ type, select, true {Rediger} false {Opret} other {Andet}} Meddeler",
|
||||
"notifiers": "Meddelere",
|
||||
"notifiers_sub": "Få notifikationer om kommende vedligeholdelsespåmindelser",
|
||||
"test": "Test",
|
||||
"theme_settings": "Temaindstillinger",
|
||||
"theme_settings_sub": "Temaindstillinger gemmes i din browsers lokale lager. Du kan til enhver tid ændre temaet. Hvis du har problemer med at indstille dit tema, kan du prøve at opdatere din browser.",
|
||||
"update_group": "Opdatér Gruppe",
|
||||
"update_language": "Opdater sprogfil",
|
||||
"url": "URL",
|
||||
"user_profile": "Brugerprofil",
|
||||
"user_profile_sub": "Inviter brugere, og administrer din konto."
|
||||
"github": "GitHub projekt"
|
||||
},
|
||||
"tools": {
|
||||
"actions": "Handlinger på lagerbeholdning",
|
||||
"actions_set": {
|
||||
"ensure_ids": "Sørg for aktiv-id'er",
|
||||
"ensure_ids_button": "Sørg for aktiv-id'er",
|
||||
"ensure_ids_sub": "Sikrer, at alle varer på lageret har et gyldigt asset_id felt. Dette gøres ved at finde det højeste aktuelle aktiv_id felt i databasen og anvende den næste værdi på hvert element, der har et ikke sat aktiv_id felt. Dette gøres i rækkefølge efter feltet opret_den.",
|
||||
"ensure_import_refs": "Sørg for importreferencer",
|
||||
"ensure_import_refs_button": "Sørg for importreferencer",
|
||||
"ensure_import_refs_sub": "Sikrer, at alle varer på lageret har et gyldigt import_ref felt. Dette gøres ved tilfældigt at generere en streng på 8 tegn for hvert element, der har et uindstillet import_ref felt.",
|
||||
"set_primary_photo": "Indstil primært foto",
|
||||
"set_primary_photo_button": "Indstil primært foto",
|
||||
"set_primary_photo_sub": "I version v0.10.0 af Homebox blev det primære billedfelt tilføjet til vedhæftede filer af typen foto. Denne handling indstiller det primære billedfelt til det første billede i matrixen for vedhæftede filer i databasen, hvis det ikke allerede er angivet. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'Se GitHub PR #576'</a>'",
|
||||
"zero_datetimes": "Nul Vare Dato Tider",
|
||||
"zero_datetimes_button": "Nul Varedato Tider",
|
||||
"zero_datetimes_sub": "Nulstiller klokkeslætsværdien for alle dato- og klokkeslætsfelter i lageret til begyndelsen af datoen. Dette er for at rette en fejl, der blev introduceret tidligt i udviklingen af webstedet, der forårsagede, at tidsværdien blev gemt med tiden, hvilket forårsagede problemer med datofelter, der viste nøjagtige værdier. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'Se Github-udgave #236 for flere detaljer.'</a>'"
|
||||
},
|
||||
"actions_sub": "Anvend flere handlinger på din beholdning på én gang. Det er uigenkaldelige handlinger. '<b>'Vær forsigtig.'</b>'",
|
||||
"import_export": "Importer/Eksporter",
|
||||
"import_export_set": {
|
||||
"export": "Eksporter inventar",
|
||||
"export_button": "Eksporter inventar",
|
||||
"export_sub": "Eksporterer standard CSV-formatet til Homebox. Dette vil eksportere alle varer i dit lager.",
|
||||
"import": "Importeret beholdning",
|
||||
"import_button": "Importer beholdning",
|
||||
"import_sub": "Importerer standard CSV-formatet til Homebox. Uden en '<code>'HB.import_ref'</code>'-kolonne vil dette '<b>'ikke'</b>' overskrive eksisterende genstande i dit lager, kun tilføje nye genstande. Rækker med kolonnen \"<code>HB.import_ref\"</code> flettes ind i eksisterende elementer med samme import_ref, hvis der findes en."
|
||||
},
|
||||
"import_export_sub": "Importér og eksporter din lagerbeholdning til og fra en CSV-fil. Dette er nyttigt til at migrere dit lager til en ny forekomst af Homebox.",
|
||||
"reports": "Rapporter",
|
||||
"reports_set": {
|
||||
"asset_labels": "Etiketter for aktiv-id",
|
||||
"asset_labels_button": "Etiket generator",
|
||||
"asset_labels_sub": "Genererer en PDF-fil, der kan udskrives, med etiketter til en række aktiv-id'er. Disse er ikke specifikke for din beholdning, så du er i stand til at udskrive etiketter på forhånd og anvende dem på din beholdning, når du modtager dem.",
|
||||
"bill_of_materials": "Stykliste",
|
||||
"bill_of_materials_button": "Generer stykliste",
|
||||
"bill_of_materials_sub": "Genererer en CSV-fil (kommaseparerede værdier), der kan importeres til et regnearksprogram. Dette er en oversigt over din beholdning med grundlæggende vare- og prisoplysninger."
|
||||
},
|
||||
"reports_sub": "Generer forskellige rapporter for dit lager."
|
||||
"bill_of_materials": "Stykliste"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,22 +2,16 @@
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Das Verhalten beim Importieren mit bestehenden import_refs hat sich geändert. Wenn ein import_ref in der CSV-Datei vorhanden ist, \nwird der Gegenstand mit den Werten in der CSV-Datei aktualisiert.",
|
||||
"change_warning": "Das Verhalten beim Importieren vorhandener import_refs hat sich geändert. Wenn ein import_ref in der CSV-Datei vorhanden ist, \nwird der Gegenstand mit den Werten in der CSV-Datei aktualisiert.",
|
||||
"description": "Importiere eine CSV-Datei, die deine Gegenstände, Etiketten und Standorte enthält. Schau in die Dokumentation für weitere Informationen\nzum erforderlichen Format.",
|
||||
"title": "CSV-Datei importieren",
|
||||
"upload": "Hochladen"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"copy_text": {
|
||||
"documentation": "Dokumentation",
|
||||
"failed_to_copy": "Text konnte nicht in die Zwischenablage kopiert werden",
|
||||
"https_required": "weil https erforderlich ist",
|
||||
"learn_more": "Erfahren Sie mehr in unserer"
|
||||
},
|
||||
"date_time": {
|
||||
"ago": "vor {0}",
|
||||
"days": "Tagen",
|
||||
"days": "Tage",
|
||||
"hour": "Stunde",
|
||||
"hours": "Stunden",
|
||||
"in": "in {0}",
|
||||
@@ -27,13 +21,13 @@
|
||||
"last-year": "letztes Jahr",
|
||||
"minute": "Minute",
|
||||
"minutes": "Minuten",
|
||||
"months": "Monaten",
|
||||
"months": "Monate",
|
||||
"next-month": "nächster Monat",
|
||||
"next-week": "nächste Woche",
|
||||
"next-week": "Nächste Woche",
|
||||
"next-year": "nächstes Jahr",
|
||||
"second": "Sekunde",
|
||||
"seconds": "Sekunden",
|
||||
"tomorrow": "morgen",
|
||||
"tomorrow": "Morgen",
|
||||
"week": "Woche",
|
||||
"weeks": "Wochen",
|
||||
"years": "Jahre",
|
||||
@@ -48,8 +42,8 @@
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Gegenstandsbezeichnung",
|
||||
"item_name": "Gegenstandsname",
|
||||
"item_description": "Artikelbezeichnung",
|
||||
"item_name": "Artikelname",
|
||||
"photo_button": "Foto 📷",
|
||||
"title": "Gegenstand erstellen"
|
||||
},
|
||||
@@ -68,15 +62,15 @@
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Label-Beschreibung",
|
||||
"label_name": "Label-Name",
|
||||
"label_description": "Label Beschreibung",
|
||||
"label_name": "Name Etikett",
|
||||
"title": "Label erstellen"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Standortbeschreibung",
|
||||
"location_name": "Standortname",
|
||||
"location_name": "Standortnamen",
|
||||
"title": "Standort erstellen"
|
||||
},
|
||||
"selector": {
|
||||
@@ -103,7 +97,7 @@
|
||||
"github": "GitHub-Projekt",
|
||||
"items": "Gegenstände",
|
||||
"join_discord": "Discord beitreten",
|
||||
"labels": "Kennzeichnung",
|
||||
"labels": "Etiketten",
|
||||
"locations": "Lagerorte",
|
||||
"maintenance": "Wartung",
|
||||
"name": "Name",
|
||||
@@ -183,7 +177,7 @@
|
||||
"purchase_price": "Einkaufspreis",
|
||||
"purchased_from": "Eingekauft von",
|
||||
"quantity": "Menge",
|
||||
"query_id": "Abfrage der Asset-ID-Nummer: { id }",
|
||||
"query_id": "Abfrage der Anlagen-ID-Nummer: { id }",
|
||||
"receipt": "Beleg",
|
||||
"receipts": "Quittungen",
|
||||
"reset_search": "Suche zurücksetzen",
|
||||
@@ -231,10 +225,6 @@
|
||||
"zh-MO": "Chinesisch (Macao)",
|
||||
"zh-TW": "Chinesisch (Traditionell)"
|
||||
},
|
||||
"languages.da-DK": "Dänisch",
|
||||
"languages.fi.FI": "Finnisch",
|
||||
"languages.ro-RO": "Rumänisch",
|
||||
"languages.sk-SK": "Slowakisch",
|
||||
"locations": {
|
||||
"child_locations": "Unter-Standorte",
|
||||
"collapse_tree": "Baum einklappen",
|
||||
@@ -305,7 +295,7 @@
|
||||
"new_password": "Neues Passwort",
|
||||
"no_notifiers": "Keine Benachrichtigungen konfiguriert",
|
||||
"notifier_modal": "{ type, select, true {Bearbeiten} false {Erstellen} other {Andere}} Notifier",
|
||||
"notifiers": "Benachrichtigungen",
|
||||
"notifiers": "Melder",
|
||||
"notifiers_sub": "Erhalte Benachrichtigungen über bevorstehende Wartungserinnerungen",
|
||||
"test": "Test",
|
||||
"theme_settings": "Themes",
|
||||
@@ -317,7 +307,7 @@
|
||||
"user_profile_sub": "Lade Benutzer ein und verwalte dein Konto."
|
||||
},
|
||||
"tools": {
|
||||
"actions": "Inventar-Aktionen",
|
||||
"actions": "Inventar Aktionen",
|
||||
"actions_set": {
|
||||
"ensure_ids": "Sicherstellen von Asset-IDs",
|
||||
"ensure_ids_button": "Sicherstellen von Asset-IDs",
|
||||
@@ -329,7 +319,7 @@
|
||||
"set_primary_photo_button": "Primäres Foto festlegen",
|
||||
"set_primary_photo_sub": "In Homebox Version v0.10.0 wurde die Auswahl des Primärbilds von angehängten Bildern hinzugefügt. Mit dieser Funktion wird für jeden Artikel ohne Primärbild das erste angehängt Bild als solches definiert. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'See GitHub PR #576'</a>'",
|
||||
"zero_datetimes": "Leeren der Datum & Zeiten der Elemente",
|
||||
"zero_datetimes_button": "Gegenstands-Datum/Zeit zurücksetzen",
|
||||
"zero_datetimes_button": "Null-Punkt-Datum-Zeiten",
|
||||
"zero_datetimes_sub": "Setzt den Zeitwert für alle Datums-Zeit-Felder in Ihrem Inventar auf den Anfang des Datums zurück. Damit wird ein Fehler behoben, der zu Beginn der Entwicklung der Website eingeführt wurde und dazu führte, dass das Datum zusammen mit der Uhrzeit gespeichert wurde, was zu Problemen bei der Anzeige von genauen Werten in Datumsfeldern führte. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'See Github Issue #236 for more details.'</a>'"
|
||||
},
|
||||
"actions_sub": "Aktionen in großen Mengen auf das Inventar anwenden. Diese Aktionen sind unumkehrbar. '<b>'Sei vorsichtig.'</b>'",
|
||||
|
||||
@@ -6,13 +6,6 @@
|
||||
"description": "Import a CSV file containing your items, labels, and locations. See documentation for more information on the \nrequired format.",
|
||||
"title": "Import CSV File",
|
||||
"upload": "Upload"
|
||||
},
|
||||
"outdated": {
|
||||
"current_version": "Current Version",
|
||||
"latest_version": "Latest Version",
|
||||
"new_version_available": "New Version Available",
|
||||
"new_version_available_link": "Click here to view the release notes",
|
||||
"dismiss": "Dismiss"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
@@ -45,12 +38,6 @@
|
||||
},
|
||||
"password_score": {
|
||||
"password_strength": "Password Strength"
|
||||
},
|
||||
"copy_text": {
|
||||
"failed_to_copy": "Failed to copy text to clipboard",
|
||||
"https_required": "because HTTPS is required",
|
||||
"learn_more": "Learn more in our",
|
||||
"documentation": "documentation"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
@@ -238,10 +225,6 @@
|
||||
"zh-MO": "Chinese (Macau)",
|
||||
"zh-TW": "Chinese (Traditional)"
|
||||
},
|
||||
"languages.da-DK": "Danish",
|
||||
"languages.fi.FI": "Finnish",
|
||||
"languages.ro-RO": "Romanian",
|
||||
"languages.sk-SK": "Slovak",
|
||||
"locations": {
|
||||
"child_locations": "Child Locations",
|
||||
"collapse_tree": "Collapse Tree",
|
||||
|
||||
@@ -9,14 +9,8 @@
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"copy_text": {
|
||||
"documentation": "documentación",
|
||||
"failed_to_copy": "No se ha podido copiar el texto al portapapeles",
|
||||
"https_required": "porque se requiere HTTPS",
|
||||
"learn_more": "Obtener más información en nuestra"
|
||||
},
|
||||
"date_time": {
|
||||
"ago": "Hace {0}",
|
||||
"ago": "hace {0}",
|
||||
"days": "días",
|
||||
"hour": "hora",
|
||||
"hours": "horas",
|
||||
@@ -62,25 +56,25 @@
|
||||
},
|
||||
"table": {
|
||||
"page": "Página",
|
||||
"rows_per_page": "Filas por página"
|
||||
"rows_per_page": "Renglones por página"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Descripción de la etiqueta",
|
||||
"label_name": "Nombre de la Etiqueta",
|
||||
"label_name": "Nombre de la etiqueta",
|
||||
"title": "Crear Etiqueta"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Descripción de la Ubicación",
|
||||
"location_name": "Nombre de la Ubicación",
|
||||
"location_description": "Descripción de la ubicación",
|
||||
"location_name": "Nombre de la ubicación",
|
||||
"title": "Crear Ubicación"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Ubicación Padre"
|
||||
"parent_location": "Ubicación padre"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "No hay ubicaciones disponibles. Añade nuevas ubicaciones mediante el botón de\n`<`span class=\"link-primary\"`>`Crear`<`/span`>` en la barra de navegación."
|
||||
@@ -88,7 +82,7 @@
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Añadir",
|
||||
"add": "Agregar",
|
||||
"build": "Compilación: { build }",
|
||||
"confirm": "Confirmar",
|
||||
"create": "Crear",
|
||||
@@ -121,12 +115,12 @@
|
||||
"home": {
|
||||
"labels": "Etiquetas",
|
||||
"quick_statistics": "Estadísticas rápidas",
|
||||
"recently_added": "Añadidos Recientemente",
|
||||
"recently_added": "Añadidos recientemente",
|
||||
"storage_locations": "Ubicaciones de almacenamiento",
|
||||
"total_items": "Artículos Totales",
|
||||
"total_labels": "Etiquetas Totales",
|
||||
"total_locations": "Ubicaciones Totales",
|
||||
"total_value": "Valor Total"
|
||||
"total_items": "Total artículos",
|
||||
"total_labels": "Total étiquetas",
|
||||
"total_locations": "Total ubicaciónes",
|
||||
"total_value": "Valor total"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Registro Desactivado",
|
||||
@@ -147,7 +141,7 @@
|
||||
"asset_id": "Activo ID",
|
||||
"attachment": "Adjunto",
|
||||
"attachments": "Adjuntos",
|
||||
"changes_persisted_immediately": "Los cambios en los archivos adjuntos se guardarán inmediatamente",
|
||||
"changes_persisted_immediately": "Los cambios a los archivos adjuntos se guardaran inmediatamente",
|
||||
"created_at": "Creado El",
|
||||
"custom_fields": "Campos Personalizados",
|
||||
"description": "Descripción",
|
||||
@@ -160,12 +154,12 @@
|
||||
"include_archive": "Incluir Elementos Archivados",
|
||||
"insured": "Asegurado",
|
||||
"last": "Último",
|
||||
"lifetime_warranty": "Garantía Permanente",
|
||||
"lifetime_warranty": "Garantia de por vida",
|
||||
"location": "Ubicación",
|
||||
"manual": "Manual",
|
||||
"manuals": "Manuales",
|
||||
"manufacturer": "Fabricante",
|
||||
"model_number": "Número de Modelo",
|
||||
"model_number": "Número de modelo",
|
||||
"name": "Nombre",
|
||||
"negate_labels": "Negar Etiquetas Seleccionadas",
|
||||
"next_page": "Siguiente Página",
|
||||
@@ -174,13 +168,13 @@
|
||||
"options": "Opciones",
|
||||
"order_by": "Ordenar Por",
|
||||
"pages": "Página { page } de { totalPages }",
|
||||
"parent_item": "Artículo Padre",
|
||||
"parent_item": "Articulo Padre",
|
||||
"photo": "Foto",
|
||||
"photos": "Fotos",
|
||||
"prev_page": "Anterior Página",
|
||||
"purchase_date": "Fecha de Compra",
|
||||
"purchase_details": "Detalles de Compra",
|
||||
"purchase_price": "Precio de Compra",
|
||||
"purchase_date": "Fecha de compra",
|
||||
"purchase_details": "Detalles de compra",
|
||||
"purchase_price": "Precio de compra",
|
||||
"purchased_from": "Comprado de",
|
||||
"quantity": "Cantidad",
|
||||
"query_id": "Consultar Número ID del Activo: { id }",
|
||||
@@ -189,9 +183,9 @@
|
||||
"reset_search": "Restablecer Búsqueda",
|
||||
"results": "{ total } Resultados",
|
||||
"serial_number": "Número de serie",
|
||||
"show_advanced_view_options": "Mostrar Opciones Avanzadas de Vista",
|
||||
"show_advanced_view_options": "Mostrar opciones avanzadas de vista",
|
||||
"sold_at": "Vendido el",
|
||||
"sold_details": "Detalles de Venta",
|
||||
"sold_details": "Detalles de venta",
|
||||
"sold_price": "Precio de venta",
|
||||
"sold_to": "Vendido a",
|
||||
"tip_1": "Los filtros de ubicación y etiquetas utilizan el operador \"OR\". Si se selecciona más de uno, sólo uno será\n necesario para obtener una coincidencia.",
|
||||
@@ -200,13 +194,13 @@
|
||||
"tips": "Sugerencias",
|
||||
"tips_sub": "Sugerencias de Búsqueda",
|
||||
"updated_at": "Actualizado El",
|
||||
"warranty": "Garantía",
|
||||
"warranty_details": "Detalles de Garantía",
|
||||
"warranty_expires": "Expiración Garantía"
|
||||
"warranty": "Garantia",
|
||||
"warranty_details": "Detalles de garantía",
|
||||
"warranty_expires": "La garantia expira"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Etiquetas No Encontradas",
|
||||
"update_label": "Actualizar Etiqueta"
|
||||
"update_label": "Actualizar etiqueta"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Catalán",
|
||||
@@ -216,11 +210,11 @@
|
||||
"fr": "Francés",
|
||||
"hu": "Húngaro",
|
||||
"it": "Italiano",
|
||||
"ja-JP": "Japonés",
|
||||
"ja-JP": "Japones",
|
||||
"nl": "Holandés",
|
||||
"pl": "Polaco",
|
||||
"pt-BR": "Portugués (Brasil)",
|
||||
"pt-PT": "Portugués (Portugal)",
|
||||
"pt-PT": "Portugués",
|
||||
"ru": "Ruso",
|
||||
"sl": "Esloveno",
|
||||
"sv": "Sueco",
|
||||
@@ -231,15 +225,11 @@
|
||||
"zh-MO": "Chino (Macao)",
|
||||
"zh-TW": "Chino (Tradicional)"
|
||||
},
|
||||
"languages.da-DK": "Danés",
|
||||
"languages.fi.FI": "Finlandés",
|
||||
"languages.ro-RO": "Rumano",
|
||||
"languages.sk-SK": "Eslovaco",
|
||||
"locations": {
|
||||
"child_locations": "Ubicaciones Hijas",
|
||||
"collapse_tree": "Colapsar Árbol",
|
||||
"child_locations": "Ubicaciones hijas",
|
||||
"collapse_tree": "Colapsar árbol",
|
||||
"no_results": "Ubicaciones No Encontradas",
|
||||
"update_location": "Actualizar Ubicación"
|
||||
"update_location": "Actualizar ubicación"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
@@ -277,7 +267,7 @@
|
||||
"total_entries": "Total de Entradas"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Artículo / Activo",
|
||||
"create_item": "Articulo / Activo",
|
||||
"create_label": "Etiqueta",
|
||||
"create_location": "Ubicación",
|
||||
"home": "Inicio",
|
||||
|
||||
@@ -3,42 +3,12 @@
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Le comportement lors d’importations avec des import_ref existants a changé. Si une valeur pour import_ref est présente dans le \nfichier CSV, alors l’élément sera mis à jour avec celle-ci.",
|
||||
"description": "Importer un fichier CSV contenant vos articles, étiquettes, et emplacements. Se reporter à la documentation pour plus d’informations \nsur le format requis.",
|
||||
"description": "Importer un fichier CSV contenant vos articles, étiquettes, et emplacements. Voir la documentation pour plus d’informations \nsur le format requis.",
|
||||
"title": "Importer un fichier CSV",
|
||||
"upload": "Téléverser"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"copy_text": {
|
||||
"documentation": "la documentation",
|
||||
"failed_to_copy": "Échec de la copie du texte dans le presse-papiers",
|
||||
"https_required": "parce que HTTPS est requis",
|
||||
"learn_more": "Pour en savoir plus, consultez notre"
|
||||
},
|
||||
"date_time": {
|
||||
"ago": "Il y a {0}",
|
||||
"days": "jours",
|
||||
"hour": "heure",
|
||||
"hours": "heures",
|
||||
"in": "autour de {0}",
|
||||
"just-now": "À l'instant",
|
||||
"last-month": "Le mois dernier",
|
||||
"last-week": "la semaine dernière",
|
||||
"last-year": "l'année dernière",
|
||||
"minute": "minute",
|
||||
"minutes": "minutes",
|
||||
"months": "mois",
|
||||
"next-month": "Le mois prochain",
|
||||
"next-week": "la semaine prochaine",
|
||||
"next-year": "l'année prochaine",
|
||||
"second": "seconde",
|
||||
"seconds": "secondes",
|
||||
"tomorrow": "demain",
|
||||
"week": "semaine",
|
||||
"weeks": "semaines",
|
||||
"years": "années",
|
||||
"yesterday": "hier"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "URL de la page"
|
||||
},
|
||||
@@ -48,8 +18,6 @@
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Description de l'article",
|
||||
"item_name": "Nom de l'article",
|
||||
"photo_button": "Photo 📷",
|
||||
"title": "Créer un article"
|
||||
},
|
||||
@@ -57,47 +25,31 @@
|
||||
"selectable": {
|
||||
"card": "Carte",
|
||||
"items": "Articles",
|
||||
"no_items": "Aucun article à afficher",
|
||||
"no_items": "Pas d'articles à afficher",
|
||||
"table": "Tableau"
|
||||
},
|
||||
"table": {
|
||||
"page": "Page",
|
||||
"rows_per_page": "Lignes par page"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Description de l'étiquette",
|
||||
"label_name": "Nom de l'étiquette",
|
||||
"title": "Créer une étiquette"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Description de l'emplacement",
|
||||
"location_name": "Nom de l'emplacement",
|
||||
"title": "Créer un emplacement"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Emplacement parent"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Aucun emplacement disponible. Créez votre premier emplacement avec\nle bouton `<`span class=\"link-primary\"`>`Créer`<`/span`>` dans la barre de navigation."
|
||||
"no_locations": "Aucun emplacement disponible. Ajoutez votre premiers emplacements avec\nle bouton `<`span class=\"link-primary\"`>`Créer`<`/span`>` dans la barre de navigation."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Ajouter",
|
||||
"build": "Version : { build }",
|
||||
"build": "Assemblage : { build }",
|
||||
"confirm": "Confirmer",
|
||||
"create": "Créer",
|
||||
"create_and_add": "Créer et en ajouter un autre",
|
||||
"created": "Créé",
|
||||
"delete": "Supprimer",
|
||||
"details": "Détails",
|
||||
"duplicate": "Dupliquer",
|
||||
"edit": "Modifier",
|
||||
"email": "Courriel",
|
||||
"follow_dev": "Suivre le développeur",
|
||||
"github": "Projet GitHub",
|
||||
@@ -105,29 +57,15 @@
|
||||
"join_discord": "Rejoindre le Discord",
|
||||
"labels": "Étiquettes",
|
||||
"locations": "Emplacements",
|
||||
"maintenance": "Maintenance",
|
||||
"name": "Nom",
|
||||
"password": "Mot de passe",
|
||||
"read_docs": "Lire la documentation",
|
||||
"save": "Enregistrer",
|
||||
"search": "Rechercher",
|
||||
"sign_out": "Se déconnecter",
|
||||
"submit": "Soumettre",
|
||||
"update": "Mettre à jour",
|
||||
"value": "Valeur",
|
||||
"version": "Version : { version }",
|
||||
"welcome": "Bienvenue, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Étiquettes",
|
||||
"quick_statistics": "Statistiques rapides",
|
||||
"recently_added": "Ajouté récemment",
|
||||
"storage_locations": "Lieu de stockage",
|
||||
"total_items": "Total d'objets",
|
||||
"total_labels": "Total d'étiquettes",
|
||||
"total_locations": "Total de lieu",
|
||||
"total_value": "Valeur total"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Les inscriptions sont désactivées",
|
||||
"dont_join_group": "Vous ne voulez pas joindre un groupe ?",
|
||||
@@ -142,71 +80,32 @@
|
||||
},
|
||||
"items": {
|
||||
"add": "Ajouter",
|
||||
"advanced": "Avancée",
|
||||
"archived": "Archivé",
|
||||
"asset_id": "ID d'élément",
|
||||
"attachment": "Pièce jointe",
|
||||
"attachments": "Pièces jointes",
|
||||
"changes_persisted_immediately": "Les changements de pièces jointes vont être sauvegardés immédiatement",
|
||||
"created_at": "Créé à",
|
||||
"custom_fields": "Champs personnalisés",
|
||||
"description": "Description",
|
||||
"details": "Détails",
|
||||
"drag_and_drop": "Glissez-déposez les fichiers ici ou cliquez pour choisir des fichiers",
|
||||
"edit_details": "Éditez les détails",
|
||||
"field_selector": "Sélecteur de champ",
|
||||
"field_value": "Valeur du champ",
|
||||
"first": "Premier",
|
||||
"include_archive": "Inclure les éléments archivés",
|
||||
"insured": "Assurée",
|
||||
"last": "Dernier",
|
||||
"lifetime_warranty": "Garantie à vie",
|
||||
"location": "Lieu",
|
||||
"manual": "Mode d'emploi",
|
||||
"manuals": "Modes d'emplois",
|
||||
"manufacturer": "Fabricant",
|
||||
"model_number": "Numéro de modèle",
|
||||
"name": "Nom",
|
||||
"negate_labels": "Négliger les étiquettes sélectionnées",
|
||||
"next_page": "Page suivante",
|
||||
"no_results": "Aucun élément trouvé",
|
||||
"notes": "Notes",
|
||||
"options": "Options",
|
||||
"order_by": "Trier par",
|
||||
"pages": "Page { page } sur { totalPages }",
|
||||
"parent_item": "Objet parent",
|
||||
"photo": "Photo",
|
||||
"photos": "Photos",
|
||||
"prev_page": "Page précédente",
|
||||
"purchase_date": "Date d'achat",
|
||||
"purchase_details": "Détail de l'achat",
|
||||
"purchase_price": "Prix d'achat",
|
||||
"purchased_from": "Acheté à",
|
||||
"quantity": "Quantité",
|
||||
"query_id": "Interrogation du numéro d'identification de l'actif : { id }",
|
||||
"receipt": "Reçu",
|
||||
"receipts": "Reçus",
|
||||
"reset_search": "Réinitialiser la recherche",
|
||||
"results": "{ total } résultats",
|
||||
"serial_number": "Numéro de série",
|
||||
"show_advanced_view_options": "Afficher les options avancées",
|
||||
"sold_at": "Vendu à",
|
||||
"sold_details": "Détails de la vente",
|
||||
"sold_price": "Prix de vente",
|
||||
"sold_to": "Vendu pour",
|
||||
"tip_1": "Les filtres d’emplacement et d’étiquette utilisent l’opérateur « OU ».\nUn seul des filtres n’a besoin de correspondre pour retourner un résultat.",
|
||||
"tip_2": "Les recherches préfixées par '#'' rechercheront un ID d'actif (exemple '#000-001')",
|
||||
"tip_3": "Les filtres de champ utilisent l’opérateur « OU ».\nUn seul des filtres n’a besoin de correspondre pour retourner un résultat.",
|
||||
"tips": "Conseils",
|
||||
"tips_sub": "Conseils pour la recherche",
|
||||
"updated_at": "Mis à jour le",
|
||||
"warranty": "Garantie",
|
||||
"warranty_details": "Détails de la garantie",
|
||||
"warranty_expires": "Expiration de la garantie"
|
||||
"updated_at": "Mis à jour le"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Aucune étiquette trouvée",
|
||||
"update_label": "Mettre à jour l'étiquette"
|
||||
"no_results": "Aucune étiquette trouvée"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Catalan",
|
||||
@@ -216,30 +115,20 @@
|
||||
"fr": "Français",
|
||||
"hu": "Hongrois",
|
||||
"it": "Italien",
|
||||
"ja-JP": "Japonais",
|
||||
"nl": "Néerlandais",
|
||||
"pl": "Polonais",
|
||||
"pt-BR": "Portugais (Brésil)",
|
||||
"pt-PT": "Portugais (Portugal)",
|
||||
"ru": "Russe",
|
||||
"sl": "Slovène",
|
||||
"sv": "Suédois",
|
||||
"tr": "Turc",
|
||||
"uk-UA": "Ukrainien",
|
||||
"zh-CN": "Chinois (simplifié)",
|
||||
"zh-HK": "Chinois (Hong Kong)",
|
||||
"zh-MO": "Chinois (Macao)",
|
||||
"zh-TW": "Chinois (traditionnel)"
|
||||
},
|
||||
"languages.da-DK": "Danois",
|
||||
"languages.fi.FI": "Finnois",
|
||||
"languages.ro-RO": "Roumain",
|
||||
"languages.sk-SK": "Slovaque",
|
||||
"locations": {
|
||||
"child_locations": "Lieu enfant",
|
||||
"collapse_tree": "Minimiser la liste",
|
||||
"no_results": "Aucun emplacement trouvé",
|
||||
"update_location": "Mettre à jour le lieu"
|
||||
"no_results": "Aucun emplacement trouvé"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
@@ -269,17 +158,14 @@
|
||||
},
|
||||
"monthly_average": "Moyenne mensuelle",
|
||||
"toast": {
|
||||
"failed_to_create": "Échec de création de l'entrée",
|
||||
"failed_to_delete": "Échec de suppression de l'entrée",
|
||||
"failed_to_create": "Échec de suppression de l'entrée",
|
||||
"failed_to_delete": "Échec de création de l'entrée",
|
||||
"failed_to_update": "Échec de mise à jour de l'entrée"
|
||||
},
|
||||
"total_cost": "Coût total",
|
||||
"total_entries": "Nombre d'entrées"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Objet / Ressource",
|
||||
"create_label": "Étiquette",
|
||||
"create_location": "Lieu",
|
||||
"home": "Accueil",
|
||||
"locations": "Emplacements",
|
||||
"maintenance": "Maintenance",
|
||||
@@ -296,7 +182,6 @@
|
||||
"delete_account_sub": "Supprimer le compte et toutes ses données. Aucune récupération possible.",
|
||||
"display_header": "{ currentValue, select, true {Masquer l’en-tête} false {Afficher l’en-tête} other {Not Hit}}",
|
||||
"enabled": "Activé",
|
||||
"example": "Example",
|
||||
"gen_invite": "Générer un lien d’invitation",
|
||||
"group_settings": "Paramètres du groupe",
|
||||
"group_settings_sub": "Paramètres du groupe partagé. Il peut être nécessaire de recharger la page pour qu’ils deviennent effectifs.",
|
||||
|
||||
@@ -9,19 +9,6 @@
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "{0} ezelőtt",
|
||||
"in": "{0} múlva",
|
||||
"just-now": "épp most",
|
||||
"last-month": "múlt hónapban",
|
||||
"last-week": "múlt héten",
|
||||
"last-year": "tavaly",
|
||||
"next-month": "jövő hónapban",
|
||||
"next-week": "jövő héten",
|
||||
"next-year": "jövőre",
|
||||
"tomorrow": "holnap",
|
||||
"yesterday": "tegnap"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "Oldal URL-je"
|
||||
},
|
||||
@@ -31,8 +18,6 @@
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Tétel leírása",
|
||||
"item_name": "Tétel neve",
|
||||
"photo_button": "Fénykép 📷",
|
||||
"title": "Új elem létrehozása"
|
||||
},
|
||||
@@ -42,45 +27,29 @@
|
||||
"items": "Tételek",
|
||||
"no_items": "Nincs megjeleníthető elem",
|
||||
"table": "Táblázat"
|
||||
},
|
||||
"table": {
|
||||
"page": "Oldal",
|
||||
"rows_per_page": "Sorok oldalanként"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Címke leírása",
|
||||
"label_name": "Címke neve",
|
||||
"title": "Címke létrehozása"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Hely leírása",
|
||||
"location_name": "Hely neve",
|
||||
"title": "Új hely létrehozása"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Ezt tartalmazó hely"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Nincs elérhető hely. Adj hozzá új helyet a\n `<`span class=\"link-primary\"`>`Létrehozás`<`/span`>` gombbal a navigációs sávon."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Hozzáadás",
|
||||
"build": "Build: { build }",
|
||||
"confirm": "Megerősítés",
|
||||
"create": "Létrehozás",
|
||||
"create_and_add": "Létrehozás és újabb hozzáadása",
|
||||
"created": "Létrehozva",
|
||||
"delete": "Törlés",
|
||||
"details": "Részletek",
|
||||
"duplicate": "Másolás",
|
||||
"edit": "Szerkesztés",
|
||||
"email": "Email",
|
||||
"follow_dev": "Kövesd a fejlesztőt",
|
||||
"github": "Github projekt",
|
||||
@@ -88,29 +57,15 @@
|
||||
"join_discord": "Csatlakozz a Discordhoz",
|
||||
"labels": "Címkék",
|
||||
"locations": "Helyek",
|
||||
"maintenance": "Karbantartás",
|
||||
"name": "Név",
|
||||
"password": "Jelszó",
|
||||
"read_docs": "Olvasd el a dokumentációt",
|
||||
"save": "Mentés",
|
||||
"search": "Keresés",
|
||||
"sign_out": "Kijelentkezés",
|
||||
"submit": "Elküldés",
|
||||
"update": "Módosítás",
|
||||
"value": "Érték",
|
||||
"version": "Verzió: { version }",
|
||||
"welcome": "Üdv, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Címkék",
|
||||
"quick_statistics": "Gyors statisztika",
|
||||
"recently_added": "Nemrég hozzáadott",
|
||||
"storage_locations": "Tárolási helyek",
|
||||
"total_items": "Összes tétel",
|
||||
"total_labels": "Összes címke",
|
||||
"total_locations": "Összes hely",
|
||||
"total_value": "Teljes érték"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Regisztráció kikapcsolva",
|
||||
"dont_join_group": "Nem szeretnél csatlakozni egy csoporthoz?",
|
||||
@@ -125,71 +80,32 @@
|
||||
},
|
||||
"items": {
|
||||
"add": "Hozzáadás",
|
||||
"advanced": "Haladó",
|
||||
"archived": "Archivált",
|
||||
"asset_id": "Eszközazonosító",
|
||||
"attachment": "Melléklet",
|
||||
"attachments": "Mellékletek",
|
||||
"changes_persisted_immediately": "A mellékletek módosításai azonnal mentésre kerülnek",
|
||||
"created_at": "Létrehozás dátuma",
|
||||
"custom_fields": "Egyedi mezők",
|
||||
"description": "Leírás",
|
||||
"details": "Részletek",
|
||||
"drag_and_drop": "Húzd ide a fájlokat, vagy kattints a fájlok kiválasztásához",
|
||||
"edit_details": "Részletek szerkesztése",
|
||||
"field_selector": "Mezőválasztó",
|
||||
"field_value": "Mező értéke",
|
||||
"first": "Első",
|
||||
"include_archive": "Archivált elemek belefoglalása",
|
||||
"insured": "Biztosítva",
|
||||
"last": "Utolsó",
|
||||
"lifetime_warranty": "Élettartam garancia",
|
||||
"location": "Hely",
|
||||
"manual": "Kézikönyv",
|
||||
"manuals": "Kézikönyvek",
|
||||
"manufacturer": "Gyártó",
|
||||
"model_number": "Modellszám",
|
||||
"name": "Név",
|
||||
"negate_labels": "Címkeválasztás negálása",
|
||||
"next_page": "Következő oldal",
|
||||
"no_results": "Egy elem sem található",
|
||||
"notes": "Megjegyzések",
|
||||
"options": "Opciók",
|
||||
"order_by": "Rendezés",
|
||||
"pages": "{page}/{totalPages} oldal",
|
||||
"parent_item": "Szülő tétel",
|
||||
"photo": "Fénykép",
|
||||
"photos": "Fényképek",
|
||||
"prev_page": "Előző oldal",
|
||||
"purchase_date": "Vásárlás dátuma",
|
||||
"purchase_details": "Vásárlás részletei",
|
||||
"purchase_price": "Beszerzési ár",
|
||||
"purchased_from": "Beszerzési hely",
|
||||
"quantity": "Mennyiség",
|
||||
"query_id": "Eszközazonosító szám lekérdezése: { id }",
|
||||
"receipt": "Számla",
|
||||
"receipts": "Számlák",
|
||||
"reset_search": "Alaphelyzet",
|
||||
"results": "{total} találat",
|
||||
"serial_number": "Sorozatszám",
|
||||
"show_advanced_view_options": "További beállítások megjelenítése",
|
||||
"sold_at": "Eladás dátuma",
|
||||
"sold_details": "Eladás részletei",
|
||||
"sold_price": "Eladási ár",
|
||||
"sold_to": "Vevő",
|
||||
"tip_1": "A hely- és címkeszűrők a „vagy” műveletet használják. Ha egynél többet választasz ki,\n bármelyik egyezése esetén megjelenik a tétel.",
|
||||
"tip_2": "A '#' előtaggal ellátott keresések egy eszközazonosítót fognak lekérdezni (például '#000-001')",
|
||||
"tip_3": "A mezőszűrők a „vagy” műveletet használják. Ha egynél többet választasz ki,\n bármelyik egyezése esetén megjelenik a tétel.",
|
||||
"tips": "Tippek",
|
||||
"tips_sub": "Tippek a kereséshez",
|
||||
"updated_at": "Változtatás dátuma",
|
||||
"warranty": "Garancia",
|
||||
"warranty_details": "Garancia részletei",
|
||||
"warranty_expires": "Garancia vége"
|
||||
"updated_at": "Változtatás dátuma"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Nem található címke",
|
||||
"update_label": "Címke módosítása"
|
||||
"no_results": "Nem található címke"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Katalán",
|
||||
@@ -199,30 +115,20 @@
|
||||
"fr": "Francia",
|
||||
"hu": "Magyar",
|
||||
"it": "Olasz",
|
||||
"ja-JP": "Japán",
|
||||
"nl": "Holland",
|
||||
"pl": "Lengyel",
|
||||
"pt-BR": "Portugál (brazíliai)",
|
||||
"pt-PT": "Portugál (Portugália)",
|
||||
"ru": "Orosz",
|
||||
"sl": "Szlovén",
|
||||
"sv": "Svéd",
|
||||
"tr": "Török",
|
||||
"uk-UA": "Ukrán",
|
||||
"zh-CN": "Kínai (egyszerűsített)",
|
||||
"zh-HK": "Kínai (hongkongi)",
|
||||
"zh-MO": "Kínai (makaói)",
|
||||
"zh-TW": "Kínai (hagyományos)"
|
||||
},
|
||||
"languages.da-DK": "Dán",
|
||||
"languages.fi.FI": "Finn",
|
||||
"languages.ro-RO": "Román",
|
||||
"languages.sk-SK": "Szlovák",
|
||||
"locations": {
|
||||
"child_locations": "Tartalmazott helyek",
|
||||
"collapse_tree": "Fanézet becsukása",
|
||||
"no_results": "Nem található hely",
|
||||
"update_location": "Hely módosítása"
|
||||
"no_results": "Nem található hely"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
@@ -260,9 +166,6 @@
|
||||
"total_entries": "Összes bejegyzés"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Tétel / Eszköz",
|
||||
"create_label": "Címke",
|
||||
"create_location": "Hely",
|
||||
"home": "Kezdőlap",
|
||||
"locations": "Helyek",
|
||||
"maintenance": "Karbantartás",
|
||||
@@ -279,7 +182,6 @@
|
||||
"delete_account_sub": "Törlöd a fiókodat és az összes kapcsolódó adatot. Ezt a műveletet nem lehet visszavonni.",
|
||||
"display_header": "{ currentValue, select, true {Fejléc elrejtése} false {Fejléc megjelenítése} other{Nincs találat}}",
|
||||
"enabled": "Engedélyezve",
|
||||
"example": "Példa",
|
||||
"gen_invite": "Meghívó link létrehozása",
|
||||
"group_settings": "Csoport beállításai",
|
||||
"group_settings_sub": "Ezek a csoport közös beállításai. Lehet hogy frissítened kell az oldalt a böngésződben a beállítások megváltoztatása után.",
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"copy_text": {
|
||||
"documentation": "documentazione",
|
||||
"failed_to_copy": "Impossibile copiare il testo negli appunti",
|
||||
"https_required": "perché è richiesto HTTPS",
|
||||
"learn_more": "Troverai ulteriori informazioni in"
|
||||
},
|
||||
"date_time": {
|
||||
"ago": "{0} fa",
|
||||
"days": "giorni",
|
||||
@@ -231,10 +225,6 @@
|
||||
"zh-MO": "Cinese (Macao)",
|
||||
"zh-TW": "Cinese (tradizionale)"
|
||||
},
|
||||
"languages.da-DK": "Danese",
|
||||
"languages.fi.FI": "Finlandese",
|
||||
"languages.ro-RO": "Rumeno",
|
||||
"languages.sk-SK": "Slovacco",
|
||||
"locations": {
|
||||
"child_locations": "Ubicazione figlia",
|
||||
"collapse_tree": "Contrai albero",
|
||||
|
||||
@@ -1,351 +0,0 @@
|
||||
{
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Oppførsel for importjobber med eksisterende import_refs har blitt endret. Hvis en import_ref eksisterer i CSV-filen,\nvil objektet oppdateres med verdiene fra CSV-filen.",
|
||||
"description": "Importer en CSV-fil som inneholder alle objekter, merkelapper og lokasjoner. Konsulter dokumentasjonen for mer\ninformasjon om påkrevd format.",
|
||||
"title": "Importer CSV-fil",
|
||||
"upload": "Last opp"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "{0} siden",
|
||||
"days": "dager",
|
||||
"hour": "time",
|
||||
"hours": "timer",
|
||||
"in": "om {0}",
|
||||
"just-now": "akkurat nå",
|
||||
"last-month": "forrige måned",
|
||||
"last-week": "forrige uke",
|
||||
"last-year": "i fjor",
|
||||
"minute": "minutt",
|
||||
"minutes": "minutter",
|
||||
"months": "måneder",
|
||||
"next-month": "neste måned",
|
||||
"next-week": "neste uke",
|
||||
"next-year": "neste år",
|
||||
"second": "sekund",
|
||||
"seconds": "sekunder",
|
||||
"tomorrow": "i morgen",
|
||||
"week": "uke",
|
||||
"weeks": "uker",
|
||||
"years": "år",
|
||||
"yesterday": "i går"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "Side-URL"
|
||||
},
|
||||
"password_score": {
|
||||
"password_strength": "Passordstyrke"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Objektbeskrivelse",
|
||||
"item_name": "Objektnavn",
|
||||
"photo_button": "Foto 📷",
|
||||
"title": "Opprett objekt"
|
||||
},
|
||||
"view": {
|
||||
"selectable": {
|
||||
"card": "Kort",
|
||||
"items": "Objekter",
|
||||
"no_items": "Ingenting å vise",
|
||||
"table": "Tabell"
|
||||
},
|
||||
"table": {
|
||||
"page": "Side",
|
||||
"rows_per_page": "Rader pr. Side"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Merkelappbeskrivelse",
|
||||
"label_name": "Merkelappnavn",
|
||||
"title": "Opprett merkelapp"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Lokasjonsbeskrivelse",
|
||||
"location_name": "Lokasjonsnavn",
|
||||
"title": "Opprett lokasjon"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Overordnet lokasjon"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Ingen tilgjengelige lokasjoner. Legg til en ny lokasjon via\n `<`span class=\"link-primary\"`>`Opprett`<`/span`>`-knappen på navigasjonslinjen."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Legg til",
|
||||
"build": "Byggnummer: { build }",
|
||||
"confirm": "Bekreft",
|
||||
"create": "Opprett",
|
||||
"create_and_add": "Opprett og legg til ny",
|
||||
"created": "Opprettet",
|
||||
"delete": "Slett",
|
||||
"details": "Detaljer",
|
||||
"duplicate": "Dupliser",
|
||||
"edit": "Rediger",
|
||||
"email": "E-post",
|
||||
"follow_dev": "Følg utvikleren",
|
||||
"github": "GitHub-prosjekt",
|
||||
"items": "Objekter",
|
||||
"join_discord": "Bli med på Discord",
|
||||
"labels": "Merkelapper",
|
||||
"locations": "Lokasjoner",
|
||||
"maintenance": "Vedlikehold",
|
||||
"name": "Navn",
|
||||
"password": "Passord",
|
||||
"read_docs": "Les dokumentasjonen",
|
||||
"save": "Lagre",
|
||||
"search": "Søk",
|
||||
"sign_out": "Logg ut",
|
||||
"submit": "Send",
|
||||
"update": "Oppdater",
|
||||
"value": "Verdi",
|
||||
"version": "Versjon: { version }",
|
||||
"welcome": "Velkommen, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Merkelapper",
|
||||
"quick_statistics": "Rask statistikk",
|
||||
"recently_added": "Nylig lagt til",
|
||||
"storage_locations": "Oppbevaringslokasjoner",
|
||||
"total_items": "Antall objekter",
|
||||
"total_labels": "Antall merkelapper",
|
||||
"total_locations": "Antall lokasjoner",
|
||||
"total_value": "Total verdi"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Registrering deaktivert",
|
||||
"dont_join_group": "Vil du ikke bli med i en gruppe?",
|
||||
"joining_group": "Du holder på å bli med i en eksisterende gruppe!",
|
||||
"login": "Logg inn",
|
||||
"register": "Registrer",
|
||||
"remember_me": "Husk meg",
|
||||
"set_email": "Hva er e-postadressen din?",
|
||||
"set_name": "Hva er navnet ditt?",
|
||||
"set_password": "Angi passord",
|
||||
"tagline": "Spor, organiser og hold styr på tingene dine."
|
||||
},
|
||||
"items": {
|
||||
"add": "Legg til",
|
||||
"advanced": "Avansert",
|
||||
"archived": "Arkivert",
|
||||
"asset_id": "Asset-ID",
|
||||
"attachment": "Vedlegg",
|
||||
"attachments": "Vedlegg",
|
||||
"changes_persisted_immediately": "Endringer til vedlegg blir lagret umiddelbart",
|
||||
"created_at": "Lagt til den",
|
||||
"custom_fields": "Egendefinerte felt",
|
||||
"description": "Beskrivelse",
|
||||
"details": "Detaljer",
|
||||
"drag_and_drop": "Dra og slipp filer her, eller klikk for å bla gjennom",
|
||||
"edit_details": "Rediger detaljer",
|
||||
"field_selector": "Feltvelger",
|
||||
"field_value": "Feltverdi",
|
||||
"first": "Først",
|
||||
"include_archive": "Inkluder arkiverte objekter",
|
||||
"insured": "Forsikret",
|
||||
"last": "Sist",
|
||||
"lifetime_warranty": "Livetidsgaranti",
|
||||
"location": "Lokasjon",
|
||||
"manual": "Bruksanvisning",
|
||||
"manuals": "Bruksanvisninger",
|
||||
"manufacturer": "Produsent",
|
||||
"model_number": "Modellnummer",
|
||||
"name": "Navn",
|
||||
"negate_labels": "Se bort fra valgte merkelapper",
|
||||
"next_page": "Neste side",
|
||||
"no_results": "Ingenting funnet",
|
||||
"notes": "Notater",
|
||||
"options": "Alternativer",
|
||||
"order_by": "Sorter etter",
|
||||
"pages": "Side { page } av { totalPages }",
|
||||
"parent_item": "Overordnet objekt",
|
||||
"photo": "Bilde",
|
||||
"photos": "Bilder",
|
||||
"prev_page": "Forrige side",
|
||||
"purchase_date": "Innkjøpsdato",
|
||||
"purchase_details": "Kjkøpsdetaljer",
|
||||
"purchase_price": "Innkjøpspris",
|
||||
"purchased_from": "Kjøpt fra",
|
||||
"quantity": "Antall",
|
||||
"query_id": "Spørring for Asset ID-nummer: { id }",
|
||||
"receipt": "Kvittering",
|
||||
"receipts": "Kvitteringer",
|
||||
"reset_search": "Nullstill søk",
|
||||
"results": "{ total } resultater",
|
||||
"serial_number": "Serienummer",
|
||||
"show_advanced_view_options": "Vis avansert Vis alternativer",
|
||||
"sold_at": "Salgskanal",
|
||||
"sold_details": "Salgsdetaljer",
|
||||
"sold_price": "Salgspris",
|
||||
"sold_to": "Solgt til",
|
||||
"tip_1": "Lokasjon og merkelappfiltere bruker ’OR’-operand. Hvis mer enn én er valgt, er bare en\n påkrevd for å få et søketreff.",
|
||||
"tip_2": "Søk med ’#’-prefix vil søke etter en asset-ID (f.eks. ’#000-001’)",
|
||||
"tip_3": "Feltet filtrer med ’OR’-operand. Hvis mer enn én er valgt vil bare en være påkrevd for å få et\nsøketreff.",
|
||||
"tips": "Tips",
|
||||
"tips_sub": "Søketips",
|
||||
"updated_at": "Oppdatert den",
|
||||
"warranty": "Garanti",
|
||||
"warranty_details": "Garantidetaljer",
|
||||
"warranty_expires": "Garanti upløper"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Ingen merkelapper funnet",
|
||||
"update_label": "Oppdater merkelapp"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Katalansk",
|
||||
"de": "Tysk",
|
||||
"en": "Engelsk",
|
||||
"es": "Spansk",
|
||||
"fr": "Fransk",
|
||||
"hu": "Ungarsk",
|
||||
"it": "Italiensk",
|
||||
"ja-JP": "Japansk",
|
||||
"nl": "Nederlandsk",
|
||||
"pl": "Polsk",
|
||||
"pt-BR": "Portugisisk (Brasil)",
|
||||
"pt-PT": "Portugisisk (Portugal)",
|
||||
"ru": "Russisk",
|
||||
"sl": "Slovensk",
|
||||
"sv": "Svensk",
|
||||
"tr": "Tyrkisk",
|
||||
"uk-UA": "Ukrainsk",
|
||||
"zh-CN": "Kinesisk (forenklet)",
|
||||
"zh-HK": "Kinesisk (Hong Kong)",
|
||||
"zh-MO": "Kinesisk (Macau)",
|
||||
"zh-TW": "Kinesisk (tradisjonell)"
|
||||
},
|
||||
"languages.da-DK": "Dansk",
|
||||
"languages.fi.FI": "Finsk",
|
||||
"languages.ro-RO": "Rumensk",
|
||||
"languages.sk-SK": "Slovakisk",
|
||||
"locations": {
|
||||
"child_locations": "Underlokasjoner",
|
||||
"collapse_tree": "Slå sammen mappetre",
|
||||
"no_results": "Ingen lokasjoner funnet",
|
||||
"update_location": "Oppdater lokasjon"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "Begge",
|
||||
"completed": "Fullført",
|
||||
"scheduled": "Planlagt"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Ferdig",
|
||||
"create_first": "Opprett ditt første innlegg",
|
||||
"delete": "Slett",
|
||||
"duplicate": "Dupliser",
|
||||
"edit": "Rediger",
|
||||
"new": "Ny"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Fullført dato",
|
||||
"cost": "Kostnad",
|
||||
"delete_confirmation": "Er du sikker på at du vil slette denne oppføringen?",
|
||||
"edit_action": "Oppdater",
|
||||
"edit_title": "Rediger oppføring",
|
||||
"entry_name": "Oppføringsnavn",
|
||||
"new_action": "Opprett",
|
||||
"new_title": "Ny oppføring",
|
||||
"notes": "Notater",
|
||||
"scheduled_date": "Planlagt dato"
|
||||
},
|
||||
"monthly_average": "Månedlig gjennomsnitt",
|
||||
"toast": {
|
||||
"failed_to_create": "Kunne ikke opprette oppføring",
|
||||
"failed_to_delete": "Kunne ikke slette oppføring",
|
||||
"failed_to_update": "Kunne ikke oppdatere oppføring"
|
||||
},
|
||||
"total_cost": "Totalkostnad",
|
||||
"total_entries": "Antall oppføringer"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Objekt",
|
||||
"create_label": "Merkelapp",
|
||||
"create_location": "Lokasjon",
|
||||
"home": "Hjem",
|
||||
"locations": "Lokasjoner",
|
||||
"maintenance": "Vedlikehold",
|
||||
"profile": "Profil",
|
||||
"search": "Søk",
|
||||
"tools": "Verktøy"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Aktiv",
|
||||
"change_password": "Endre passord",
|
||||
"currency_format": "Valutaformat",
|
||||
"current_password": "Nåværende passord",
|
||||
"delete_account": "Slett konto",
|
||||
"delete_account_sub": "Slett kontoen din og alle data knyttet til den. Denne handlingen kan ikke angres.",
|
||||
"display_header": "{ currentValue, select, true {Skjul overskrift} false {Vis overskrift} other {Ingen treff}}",
|
||||
"enabled": "Aktivert",
|
||||
"example": "Eksempel",
|
||||
"gen_invite": "Opprett invitasjonslenke",
|
||||
"group_settings": "Gruppeinnstillinger",
|
||||
"group_settings_sub": "Delte gruppeinnstillinger. Du må muligens laste inn siden på nytt for at noen endringer skal aktiveres.",
|
||||
"inactive": "Inaktiv",
|
||||
"language": "Språk",
|
||||
"new_password": "Nytt passord",
|
||||
"no_notifiers": "Ingen varslingsmekanismer satt opp",
|
||||
"notifier_modal": "{ type, select, true {Rediger} false {Opprett} other {Annen}} varsling",
|
||||
"notifiers": "Varslingsmekanismer",
|
||||
"notifiers_sub": "Få varslinger for kommende vedlikeholdspåminnelser",
|
||||
"test": "Test",
|
||||
"theme_settings": "Temainnstillinger",
|
||||
"theme_settings_sub": "Temainnstillinger lagres i nettleseren din sin midlertidige lagring. Du kan endre temaet når som helst. Hvis du\n har problemer, last inn siden på nytt.",
|
||||
"update_group": "Oppdater gruppe",
|
||||
"update_language": "Oppdater språk",
|
||||
"url": "URL",
|
||||
"user_profile": "Brukerprofil",
|
||||
"user_profile_sub": "Inviter brukere og behandle kontoen din."
|
||||
},
|
||||
"tools": {
|
||||
"actions": "Inventarhandlinger",
|
||||
"actions_set": {
|
||||
"ensure_ids": "Sikre Asset IDer",
|
||||
"ensure_ids_button": "Sikre Asset IDer",
|
||||
"ensure_ids_sub": "Sikrer at alle objekter i inventarlisten har et gyldig asset_id-felt. Dette gjøres ved å finne den høyeste asset_iden i databasen og legge til neste tilgjengelige verdi til hvert objekt som ikke har en asset_id. Dette gjøres i rekkefølgen til verdien fra created_at-feltet.",
|
||||
"ensure_import_refs": "Sikre import-referanser",
|
||||
"ensure_import_refs_button": "Sikre import-referanser",
|
||||
"ensure_import_refs_sub": "Sikrer at alle objektene i inventaret har et gyldig import_ref-felt. Dette gjøres ved å opprette en tilfeldig 8-tegns tekststreng for hvert objekt som har et tomt import_ref-felt.",
|
||||
"set_primary_photo": "Angi primærbilde",
|
||||
"set_primary_photo_button": "Angi primærbilde",
|
||||
"set_primary_photo_sub": "I versjon v0.10.0 av Homebox ble det primære bildefeltet lagt til vedlegg som type foto. Denne handlingen vil sette verdien for det primære bildefeltet til det første bildet lagret i databasen, hvis det ikke allerede er angitt. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'Jfr. GitHub PR #576'</a>'",
|
||||
"zero_datetimes": "Null ut objektdatotider",
|
||||
"zero_datetimes_button": "Null ut objektdatotider",
|
||||
"zero_datetimes_sub": "Nullstiller tidsverdien for alle datotid-felter i inventaret til starten av datoen. Dette er for å fikse en bug som ble tidlig introdusert i utviklingen av siden, og forårsaket at tidsverdien ble lagret sammen med tidspunktet, noe som skapte problemer for datofelt som skulle vise korrekte verdier. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'Jfr. Github Issue #236 for flere detaljer.'</a>'"
|
||||
},
|
||||
"actions_sub": "Utfør massehandlinger for inventaret ditt. Disse handlingene er irreversible. '<b>'Vær forsiktig.'</b>'",
|
||||
"import_export": "Importer/Eksporter",
|
||||
"import_export_set": {
|
||||
"export": "Eksporter inventar",
|
||||
"export_button": "Eksporter inventar",
|
||||
"export_sub": "Eksporterer standard CSV-format for Homebox. Dette vil eksportere alle objektene i inventaret ditt.",
|
||||
"import": "Importer inventar",
|
||||
"import_button": "Importer inventar",
|
||||
"import_sub": "Importerer standard CSV-format for Homebox. Uten en '<code>'HB.import_ref'</code>'-kolonne vil dette '<b>'ikke'</b>' overskrive noen eksisterende objekter i inventaret ditt, bare legge til nye. Rader med en '<code>'HB.import_ref'</code>'-kolonne slås sammen med eksisterende objekter med samme import_ref, hvis en eksisterer."
|
||||
},
|
||||
"import_export_sub": "Importer og eksporter inventaret ditt til og fra CSV-format. Dette er nyttig for å flytte inventaret ditt til en ny instans av Homebox.",
|
||||
"reports": "Rapporter",
|
||||
"reports_set": {
|
||||
"asset_labels": "Asset-ID-merkelapper",
|
||||
"asset_labels_button": "Merkelappgenerator",
|
||||
"asset_labels_sub": "Genererer en utskrivbar PDF-fil for merkelapper for en serie Asset-Ider. Disse er ikke spesifikke for ditt inventar, så du kan lage og skrive ut merkelapper før de trengs og feste dem til inventaret ditt når det kommer.",
|
||||
"bill_of_materials": "Liste over materialer",
|
||||
"bill_of_materials_button": "Opprett liste over materialer",
|
||||
"bill_of_materials_sub": "Genererer en CSV (kommaseparerte verdier)-fil som kan importeres til et regnearkprogram. Dette er et sammendrag av inventaret ditt med grunnleggende objekt- og prisinformasjon."
|
||||
},
|
||||
"reports_sub": "Genererer forskjellige rapporter for inventaret ditt."
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,6 @@
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"copy_text": {
|
||||
"documentation": "documentatie",
|
||||
"failed_to_copy": "Kopiëren van tekst naar klembord mislukt",
|
||||
"https_required": "omdat https vereist is",
|
||||
"learn_more": "Leer meer in onze"
|
||||
},
|
||||
"date_time": {
|
||||
"ago": "{0} geleden",
|
||||
"days": "dagen",
|
||||
@@ -76,7 +70,7 @@
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Locatie omschrijving",
|
||||
"location_name": "Locatie Naam",
|
||||
"location_name": "Locatie",
|
||||
"title": "Maak locatie"
|
||||
},
|
||||
"selector": {
|
||||
@@ -96,14 +90,14 @@
|
||||
"created": "Gemaakt",
|
||||
"delete": "Verwijderen",
|
||||
"details": "Details",
|
||||
"duplicate": "Dupliceren",
|
||||
"duplicate": "Dubbel",
|
||||
"edit": "Bewerk",
|
||||
"email": "E-mail",
|
||||
"follow_dev": "Volg de ontwikkelaar",
|
||||
"github": "GitHub Project",
|
||||
"items": "artikelen",
|
||||
"join_discord": "Sluit je aan bij de Discord",
|
||||
"labels": "Labels",
|
||||
"labels": "etiketten",
|
||||
"locations": "Locaties",
|
||||
"maintenance": "Onderhoud",
|
||||
"name": "Naam",
|
||||
@@ -119,10 +113,10 @@
|
||||
"welcome": "Welkom, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Labels",
|
||||
"labels": "etiketten",
|
||||
"quick_statistics": "Snelle statistieken",
|
||||
"recently_added": "Recent toegevoegd",
|
||||
"storage_locations": "Opslaglocaties",
|
||||
"storage_locations": "Verblijfplaatsen",
|
||||
"total_items": "Totale items",
|
||||
"total_labels": "Totaal aantal labels",
|
||||
"total_locations": "Totaal aantal locaties",
|
||||
@@ -130,8 +124,8 @@
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Registratie uitgeschakeld",
|
||||
"dont_join_group": "Wil je je niet bij een groep aansluiten?",
|
||||
"joining_group": "Je sluit je aan bij een bestaande groep!",
|
||||
"dont_join_group": "Wil je niet aan een groep deelnemen?",
|
||||
"joining_group": "Je neemt deel aan een bestaande groep!",
|
||||
"login": "Log in",
|
||||
"register": "Registreer",
|
||||
"remember_me": "Onthoud mij",
|
||||
@@ -158,7 +152,7 @@
|
||||
"field_value": "Veldwaarde",
|
||||
"first": "Eerst",
|
||||
"include_archive": "Inclusief gearchiveerde items",
|
||||
"insured": "Verzekerd",
|
||||
"insured": "Verzekerde",
|
||||
"last": "Achternaam",
|
||||
"lifetime_warranty": "Levenslange garantie",
|
||||
"location": "Locatie",
|
||||
@@ -167,7 +161,7 @@
|
||||
"manufacturer": "Fabrikant",
|
||||
"model_number": "Modelnummer",
|
||||
"name": "Naam",
|
||||
"negate_labels": "Negeer Geselecteerde Labels",
|
||||
"negate_labels": "Negeer Geselecteerde Etiketten",
|
||||
"next_page": "Volgende pagina",
|
||||
"no_results": "Geen Items Gevonden",
|
||||
"notes": "Opmerkingen",
|
||||
@@ -184,12 +178,12 @@
|
||||
"purchased_from": "Gekocht van",
|
||||
"quantity": "Aantal",
|
||||
"query_id": "ID-nummer van object opvragen: { id }",
|
||||
"receipt": "Factuur",
|
||||
"receipts": "Facturen",
|
||||
"receipt": "Bewijs",
|
||||
"receipts": "Bonnetjes",
|
||||
"reset_search": "Reset Zoeken",
|
||||
"results": "{ total } Resultaten",
|
||||
"serial_number": "Serienummer",
|
||||
"show_advanced_view_options": "Geavanceerde Opties Weergeven",
|
||||
"show_advanced_view_options": "geavanceerde opties weergeven",
|
||||
"sold_at": "Verkocht bij",
|
||||
"sold_details": "Verkochte details",
|
||||
"sold_price": "Verkoopprijs",
|
||||
@@ -231,12 +225,8 @@
|
||||
"zh-MO": "Chinees (Macau)",
|
||||
"zh-TW": "Chinees (traditioneel)"
|
||||
},
|
||||
"languages.da-DK": "Deens",
|
||||
"languages.fi.FI": "Fins",
|
||||
"languages.ro-RO": "Roemeens",
|
||||
"languages.sk-SK": "Slowaaks",
|
||||
"locations": {
|
||||
"child_locations": "Sublocaties",
|
||||
"child_locations": "Kind Locaties",
|
||||
"collapse_tree": "Structuur invouwen",
|
||||
"no_results": "Geen locaties gevonden",
|
||||
"update_location": "Locatie bijwerken"
|
||||
@@ -251,30 +241,30 @@
|
||||
"complete": "Compleet",
|
||||
"create_first": "Maak je eerste invoer aan",
|
||||
"delete": "Verwijderen",
|
||||
"duplicate": "Dupliceren",
|
||||
"duplicate": "Dubbel",
|
||||
"edit": "Bewerken",
|
||||
"new": "Nieuw"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Datum Voltooid",
|
||||
"completed_date": "Voltooiings Datum",
|
||||
"cost": "Kosten",
|
||||
"delete_confirmation": "Weet u zeker dat u deze gegevens wilt verwijderen?",
|
||||
"edit_action": "Bijwerken",
|
||||
"edit_title": "Invoer bewerken",
|
||||
"entry_name": "Invoernaam",
|
||||
"edit_title": "Bewerk entry",
|
||||
"entry_name": "Ingangsnaam",
|
||||
"new_action": "Maak",
|
||||
"new_title": "Nieuwe invoer",
|
||||
"new_title": "Nieuw fragment",
|
||||
"notes": "Opmerkingen",
|
||||
"scheduled_date": "Geplande datum"
|
||||
"scheduled_date": "Gepland datum"
|
||||
},
|
||||
"monthly_average": "Maandelijks",
|
||||
"toast": {
|
||||
"failed_to_create": "Kan invoer niet maken",
|
||||
"failed_to_delete": "Kan invoer niet verwijderen",
|
||||
"failed_to_delete": "Kon item niet verwijderen",
|
||||
"failed_to_update": "Kan invoer niet bijwerken"
|
||||
},
|
||||
"total_cost": "Totale kosten",
|
||||
"total_entries": "Totaal aantal invoeren"
|
||||
"total_entries": "Totaal aantal Inzendingen"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Artikel / Object",
|
||||
@@ -285,7 +275,7 @@
|
||||
"maintenance": "Onderhoud",
|
||||
"profile": "Profiel",
|
||||
"search": "Zoeken",
|
||||
"tools": "Hulpmiddelen"
|
||||
"tools": "Gereedschappen"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Actief",
|
||||
@@ -293,27 +283,27 @@
|
||||
"currency_format": "Valutanotatie",
|
||||
"current_password": "Huidig Wachtwoord",
|
||||
"delete_account": "Verwijder account",
|
||||
"delete_account_sub": "Verwijder je account en alle bijhorende data. Deze actie kan niet ongedaan worden.",
|
||||
"delete_account_sub": "Verwijder je account en alle geassocieerde data. Deze actie kan niet ongedaan worden.",
|
||||
"display_header": "{ currentValue, select, true {Header verbergen} false {Header weergeven} other {Geen gevonden}}",
|
||||
"enabled": "Ingeschakeld",
|
||||
"enabled": "ingeschakeld",
|
||||
"example": "Voorbeeld",
|
||||
"gen_invite": "Genereer Uitnodigingslink",
|
||||
"group_settings": "Groepsinstellingen",
|
||||
"group_settings_sub": "Gedeelde groepsinstellingen. Mogelijk moet u uw browser vernieuwen om sommige instellingen toe te passen.",
|
||||
"group_settings": "Groeps Instellingen",
|
||||
"group_settings_sub": "Gedeelde groepsinstellingen. Het kan zijn dat je je browser moet verversen om alle instellingen te zien werken.",
|
||||
"inactive": "Inactief",
|
||||
"language": "Taal",
|
||||
"new_password": "Nieuw Wachtwoord",
|
||||
"no_notifiers": "Geen melders geconfigureerd",
|
||||
"notifier_modal": "{ type, select, true {Bewerk} false {Creëer} other {overig}} Notifier",
|
||||
"notifiers": "Notificatie",
|
||||
"notifiers_sub": "Ontvang meldingen voor komende onderhoudsherinneringen",
|
||||
"notifiers_sub": "Krijg notificaties voor opkomende onderhouds herinneringen",
|
||||
"test": "Test",
|
||||
"theme_settings": "Thema-instellingen",
|
||||
"theme_settings_sub": "Thema-instellingen worden opgeslagen in de lokale opslag van uw browser. Je kan deze wijzigen op elk moment. \nAls je problemen hebt met de instellingen kun je de browser verversen.",
|
||||
"theme_settings": "Theme instellingen",
|
||||
"theme_settings_sub": "Thema-instellingen worden opgeslagen in de lokale opslag van uw browser. Je kan deze wijzigen op elk moment. \nAls je problemen hebt met de instellingen kun je je browser verversen.",
|
||||
"update_group": "Groep bijwerken",
|
||||
"update_language": "Taal bijwerken",
|
||||
"url": "URL",
|
||||
"user_profile": "Gebruikersprofiel",
|
||||
"user_profile": "Gebruikers Profiel",
|
||||
"user_profile_sub": "Nodig gebruikers uit, en beheer je account."
|
||||
},
|
||||
"tools": {
|
||||
@@ -332,11 +322,11 @@
|
||||
"zero_datetimes_button": "Nul item Datum Tijden",
|
||||
"zero_datetimes_sub": "Hiermee stelt u de tijdwaarde voor alle datum-/tijdvelden in uw voorraad in op het begin van de datum. Dit is een oplossing voor een fout in de applicatie geïntroduceerd in het begin van de ontwikkeling waarbij de tijd waarde verkeerd werd opgeslagen. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'Zie Github Issue #236 voor alle details.'</a>'"
|
||||
},
|
||||
"actions_sub": "Acties in bulk toepassen op je inventaris. Deze zijn onomkeerbaar '<b>'Wees voorzichtig.'</b>'",
|
||||
"actions_sub": "Acties bulksgewijs toepassen op je voorraad. Deze zijn onomkeerbaar '<b>'Wees voorzichtig.'</b>'",
|
||||
"import_export": "Importeer/Exporteer",
|
||||
"import_export_set": {
|
||||
"export": "Exporteer voorraad",
|
||||
"export_button": "Exporteer voorraad",
|
||||
"export": "Export voorraad",
|
||||
"export_button": "Export voorraad",
|
||||
"export_sub": "Exporteert het standaard CSV-formaat voor Homebox. Dit exporteert alle items in jouw inventaris.",
|
||||
"import": "Inventaris Importeren",
|
||||
"import_button": "Inventaris Importeren",
|
||||
|
||||
@@ -2,41 +2,34 @@
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Zachowanie podczas importu z istniejącymi import_ref zostało zmienione. Jeśli import_ref jest obecny w pliku CSV, \nprzedmiot zostanie zaktualizowany wartościami z pliku CSV.",
|
||||
"change_warning": "Zachowanie przy imporcie z istniejącymi import_ref zostało zmienione. Jeśli import_ref jest obecny w pliku CSV, \nprzedmiot zostanie zaktualizowany zgodnie z wartościami w pliku CSV.",
|
||||
"description": "Zaimportuj plik CSV zawierający Twoje przedmioty, etykiety i lokalizacje. Zobacz dokumentację, aby uzyskać \nwięcej informacji na temat wymaganego formatu.",
|
||||
"title": "Zaimportuj plik CSV",
|
||||
"upload": "Prześlij"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"copy_text": {
|
||||
"documentation": "dokumentacja",
|
||||
"failed_to_copy": "Nie udało się skopiować tekstu do schowka",
|
||||
"https_required": "ponieważ wymagany jest HTTPS",
|
||||
"learn_more": "Dowiedz się więcej w naszym"
|
||||
},
|
||||
"date_time": {
|
||||
"ago": "{0} temu",
|
||||
"days": "dni",
|
||||
"hour": "godzina",
|
||||
"hours": "godziny",
|
||||
"in": "za {0}",
|
||||
"just-now": "teraz",
|
||||
"last-month": "W zeszłym miesiącu",
|
||||
"last-week": "W zeszłym tygodniu",
|
||||
"last-year": "w zeszłym roku",
|
||||
"last-month": "ostatni miesiąc",
|
||||
"last-week": "ostatni tydzień",
|
||||
"last-year": "ostatni rok",
|
||||
"minute": "minuta",
|
||||
"minutes": "minuty",
|
||||
"months": "miesięcy",
|
||||
"next-month": "w przyszłym miesiącu",
|
||||
"next-week": "w przyszłym tygodniu",
|
||||
"next-year": "w przyszłym roku",
|
||||
"months": "miesiące",
|
||||
"next-month": "następny miesiąc",
|
||||
"next-week": "następny tydzień",
|
||||
"next-year": "następny rok",
|
||||
"second": "sekunda",
|
||||
"seconds": "sekundy",
|
||||
"tomorrow": "jutro",
|
||||
"week": "tydzień",
|
||||
"weeks": "tygodnie",
|
||||
"years": "lata",
|
||||
"years": "lat",
|
||||
"yesterday": "wczoraj"
|
||||
},
|
||||
"page_qr_code": {
|
||||
@@ -62,7 +55,7 @@
|
||||
},
|
||||
"table": {
|
||||
"page": "Strona",
|
||||
"rows_per_page": "Ilość wierszy na stronę"
|
||||
"rows_per_page": "Wiersze na stronę"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -122,7 +115,6 @@
|
||||
"labels": "Etykiety",
|
||||
"quick_statistics": "Szybkie statystyki",
|
||||
"recently_added": "Ostatnio dodane",
|
||||
"storage_locations": "Miejsca przechowywania",
|
||||
"total_items": "Łączna liczba produktów",
|
||||
"total_labels": "Łączna liczba etykiet",
|
||||
"total_locations": "Łączna liczba lokalizacji",
|
||||
@@ -144,7 +136,6 @@
|
||||
"add": "Dodaj",
|
||||
"advanced": "Zaawansowane",
|
||||
"archived": "Zarchiwizowane",
|
||||
"asset_id": "Identyfikator zasobu",
|
||||
"attachment": "Załącznik",
|
||||
"attachments": "Załączniki",
|
||||
"changes_persisted_immediately": "Zmiany w załącznikach zostaną natychmiast zapisane",
|
||||
@@ -187,7 +178,7 @@
|
||||
"receipt": "Paragon",
|
||||
"receipts": "Paragony",
|
||||
"reset_search": "Zresetuj wyszukiwanie",
|
||||
"results": "{ total } wyników",
|
||||
"results": "{ total } wyniki",
|
||||
"serial_number": "Numer seryjny",
|
||||
"show_advanced_view_options": "Pokaż ustawienia zaawansowane",
|
||||
"sold_at": "Sprzedane w",
|
||||
@@ -209,32 +200,28 @@
|
||||
"update_label": "Aktualizuj etykietę"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "kataloński",
|
||||
"de": "niemiecki",
|
||||
"en": "angielski",
|
||||
"es": "hiszpański",
|
||||
"fr": "francuski",
|
||||
"hu": "węgierski",
|
||||
"it": "włoski",
|
||||
"ja-JP": "japoński",
|
||||
"nl": "holenderski",
|
||||
"pl": "polski",
|
||||
"pt-BR": "portugalski (Brazylia)",
|
||||
"pt-PT": "portugalski (Portugalia)",
|
||||
"ru": "rosyjski",
|
||||
"sl": "słoweński",
|
||||
"sv": "szwedzki",
|
||||
"tr": "turecki",
|
||||
"uk-UA": "ukraiński",
|
||||
"zh-CN": "chiński (uproszczony)",
|
||||
"zh-HK": "chiński (Hong Kong)",
|
||||
"zh-MO": "chiński (Makau)",
|
||||
"zh-TW": "chiński (tradycyjny)"
|
||||
"ca": "Kataloński",
|
||||
"de": "Niemiecki",
|
||||
"en": "Angielski",
|
||||
"es": "Hiszpański",
|
||||
"fr": "Francuski",
|
||||
"hu": "Węgierski",
|
||||
"it": "Włoski",
|
||||
"ja-JP": "Japoński",
|
||||
"nl": "Holenderski",
|
||||
"pl": "Polski",
|
||||
"pt-BR": "Portugalski (Brazylia)",
|
||||
"pt-PT": "Portugalski (Portugalia)",
|
||||
"ru": "Rosyjski",
|
||||
"sl": "Słoweński",
|
||||
"sv": "Szwedzki",
|
||||
"tr": "Turecki",
|
||||
"uk-UA": "Ukraiński",
|
||||
"zh-CN": "Chiński (uproszczony)",
|
||||
"zh-HK": "Chiński (Hong Kong)",
|
||||
"zh-MO": "Chiński (Makau)",
|
||||
"zh-TW": "Chiński (tradycyjny)"
|
||||
},
|
||||
"languages.da-DK": "duńska",
|
||||
"languages.fi.FI": "fińska",
|
||||
"languages.ro-RO": "rumuńska",
|
||||
"languages.sk-SK": "słowacka",
|
||||
"locations": {
|
||||
"child_locations": "Podlokalizacje",
|
||||
"collapse_tree": "Zwiń drzewo",
|
||||
@@ -294,12 +281,11 @@
|
||||
"current_password": "Bieżące hasło",
|
||||
"delete_account": "Usuń konto",
|
||||
"delete_account_sub": "Usuń swoje konto oraz wszystkie powiązane z nim dane. Tego nie można cofnąć.",
|
||||
"display_header": "{currentValue, select, true {Ukryj nagłówek} false {Pokaż nagłówek} other {Nie dotyczy}}",
|
||||
"enabled": "Włączone",
|
||||
"example": "Przykład",
|
||||
"gen_invite": "Wygeneruj link z zaproszeniem",
|
||||
"group_settings": "Ustawienia grupy",
|
||||
"group_settings_sub": "Ustawienia grupy udostępnione. Może być konieczne odświeżenie strony, aby niektóre ustawienia zostały zastosowane.",
|
||||
"group_settings_sub": "Ustawienia grupy udostępnione. Możesz potrzebować odświeżyć przeglądarkę, aby niektóre ustawienia zostały zastosowane.",
|
||||
"inactive": "Nieaktywny",
|
||||
"language": "Język",
|
||||
"new_password": "Nowe hasło",
|
||||
@@ -320,38 +306,11 @@
|
||||
"actions": "Akcje na zasobach",
|
||||
"actions_set": {
|
||||
"ensure_ids": "Zapewnienie identyfikatorów zasobów",
|
||||
"ensure_ids_button": "Zapewnij identyfikatory zasobów",
|
||||
"ensure_ids_sub": "Zapewnia, że wszystkie przedmioty w Twoim inwentarzu mają prawidłowe pole asset_id. W tym celu wyszukiwany jest najwyższy obecny asset_id w bazie danych, a kolejne wartości są przypisywane do przedmiotów, które nie mają ustawionego pola asset_id. Proces odbywa się w kolejności według pola created_at.",
|
||||
"ensure_import_refs": "Zapewnij odnośniki importu",
|
||||
"ensure_import_refs_button": "Zapewnij odnośniki importu",
|
||||
"ensure_import_refs_sub": "Zapewnia, że wszystkie przedmioty w Twoim inwentarzu mają prawidłowe pole import_ref. W tym celu dla każdego przedmiotu, który nie ma ustawionego pola import_ref, losowo generowany jest 8-znakowy ciąg.",
|
||||
"ensure_import_refs_sub": "Zapewnia, że wszystkie przedmioty w Twoim asortymencie mają prawidłowe pole import_ref",
|
||||
"set_primary_photo": "Ustaw główne zdjęcie",
|
||||
"set_primary_photo_button": "Ustaw główne zdjęcie",
|
||||
"set_primary_photo_sub": "W wersji v0.10.0 Homebox pole głównego obrazu zostało dodane do załączników typu zdjęcie. Ta akcja ustawi pole głównego obrazu do pierwszego zdjęcia w załącznikach z bazy danych, jeżeli nie jest już ustawione. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'Zobacz GitHub PR #576'</a>'",
|
||||
"zero_datetimes": "Wyzeruj daty i godziny przedmiotów",
|
||||
"zero_datetimes_button": "Wyzeruj daty i godziny przedmiotów",
|
||||
"zero_datetimes_sub": "Resetuje wartość czasu dla wszystkich pól daty i godziny w Twoim inwentarzu, ustawiając ją na początek dnia. Jest to rozwiązanie problemu, który pojawił się we wczesnej fazie rozwoju aplikacji, powodując zapisywanie wartości czasu wraz z datą, co skutkowało nieprawidłowym wyświetlaniem wartości w polach daty. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">Zobacz szczegóły w GitHub Issue #236</a>'"
|
||||
"set_primary_photo_sub": "W wersji v0.10.0 Homebox pole głównego obrazu zostało dodane do załączników typu zdjęcie. Ta akcja ustawi pole głównego obrazu do pierwszego zdjęcia w załącznikach z bazy danych, jeżeli nie jest już ustawione. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'Zobacz GitHub PR #576'</a>'"
|
||||
},
|
||||
"actions_sub": "Zastosuj akcje zbiorczo do swojego inwentarza. Są to działania nieodwracalne. '<b>'Bądź ostrożny.'</b>",
|
||||
"import_export": "Import/eksport",
|
||||
"import_export_set": {
|
||||
"export": "Eksportuj inwentarz",
|
||||
"export_button": "Eksportuj inwentarz",
|
||||
"export_sub": "Eksportuje standardowy format CSV dla Homebox. Zostaną wyeksportowane wszystkie przedmioty z Twojego inwentarza.",
|
||||
"import": "Importuj inwentarz",
|
||||
"import_button": "Importuj inwentarz",
|
||||
"import_sub": "Importuje standardowy format CSV dla Homebox. Jeśli plik nie zawiera kolumny '<code>'HB.import_ref'</code>', istniejące przedmioty w Twoim inwentarzu '<b>'nie'</b>' zostaną nadpisane – zostaną dodane jedynie nowe przedmioty. Wiersze z kolumną '<code>'HB.import_ref'</code>' są łączone z istniejącymi przedmiotami, które mają ten sam import_ref, jeśli taki istnieje."
|
||||
},
|
||||
"import_export_sub": "Importuj i eksportuj swój inwentarz z i do pliku CSV. Jest to przydatne podczas przenoszenia inwentarza do nowej instancji Homebox.",
|
||||
"reports": "Raporty",
|
||||
"reports_set": {
|
||||
"asset_labels": "Etykiety identyfikatora zasobu",
|
||||
"asset_labels_button": "Generator etykiet",
|
||||
"asset_labels_sub": "Generuje drukowalny plik PDF z etykietami dla zakresu identyfikatora zasobu. Nie jest on powiązany z Twoim inwentarzem, dzięki czemu możesz go wydrukować z wyprzedzeniem i zastosować do inwentarza, kiedy go otrzymasz.",
|
||||
"bill_of_materials": "Lista materiałów",
|
||||
"bill_of_materials_button": "Generuj zestawienie materiałów",
|
||||
"bill_of_materials_sub": "Generuje plik CSV (Comma Separated Values), który można zaimportować do programu arkusza kalkulacyjnego. Jest to podsumowanie Twojego inwentarza z podstawowymi informacjami o przedmiotach i cenach."
|
||||
},
|
||||
"reports_sub": "Generuj różne raporty dla swojego inwentarza."
|
||||
"import_export": "Import/eksport"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,30 +9,6 @@
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "{0} atrás",
|
||||
"days": "dias",
|
||||
"hour": "hora",
|
||||
"hours": "horas",
|
||||
"in": "em {0}",
|
||||
"just-now": "neste momento",
|
||||
"last-month": "último mês",
|
||||
"last-week": "última semana",
|
||||
"last-year": "último ano",
|
||||
"minute": "minuto",
|
||||
"minutes": "minutos",
|
||||
"months": "meses",
|
||||
"next-month": "próximo mês",
|
||||
"next-week": "próxima semana",
|
||||
"next-year": "próximo ano",
|
||||
"second": "segundo",
|
||||
"seconds": "segundos",
|
||||
"tomorrow": "amanhã",
|
||||
"week": "semana",
|
||||
"weeks": "semanas",
|
||||
"years": "anos",
|
||||
"yesterday": "ontem"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "URL da página"
|
||||
},
|
||||
@@ -42,8 +18,6 @@
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Descrição do Item",
|
||||
"item_name": "Nome do Item",
|
||||
"photo_button": "Foto📷",
|
||||
"title": "Criar Item"
|
||||
},
|
||||
@@ -53,45 +27,29 @@
|
||||
"items": "Items",
|
||||
"no_items": "Nenhum item para exibir",
|
||||
"table": "Tabela"
|
||||
},
|
||||
"table": {
|
||||
"page": "Página",
|
||||
"rows_per_page": "Linhas por página"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Descrição da Etiqueta",
|
||||
"label_name": "Nome da Etiqueta",
|
||||
"title": "Criar etiqueta"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Descrição do Local",
|
||||
"location_name": "Nome do Local",
|
||||
"title": "Criar Local"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Local Pai"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Não há locais disponíveis. Adicione novos locais\n através do botão \"Criar\" na barra de navegação."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Adicionar",
|
||||
"build": "Compilação: { build }",
|
||||
"confirm": "Confirmar",
|
||||
"create": "Criar",
|
||||
"create_and_add": "Criar e Adicionar Outro",
|
||||
"created": "Criado",
|
||||
"delete": "Excluir",
|
||||
"details": "Detalhes",
|
||||
"duplicate": "Duplicar",
|
||||
"edit": "Editar",
|
||||
"email": "Email",
|
||||
"follow_dev": "Seguir o desenvolvedor",
|
||||
"github": "Projeto GitHub",
|
||||
@@ -99,29 +57,15 @@
|
||||
"join_discord": "Junte-se ao Discord",
|
||||
"labels": "Etiquetas",
|
||||
"locations": "Locais",
|
||||
"maintenance": "Manutenção",
|
||||
"name": "Nome",
|
||||
"password": "Senha",
|
||||
"read_docs": "Leia a Documentação",
|
||||
"save": "Salvar",
|
||||
"search": "Buscar",
|
||||
"sign_out": "Sair",
|
||||
"submit": "Enviar",
|
||||
"update": "Atualizar",
|
||||
"value": "Valor",
|
||||
"version": "Versão: { version }",
|
||||
"welcome": "Bem-vindo, {username}"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Etiquetas",
|
||||
"quick_statistics": "Estatísticas Rápidas",
|
||||
"recently_added": "Adicionados Recentemente",
|
||||
"storage_locations": "Locais de Armazenamento",
|
||||
"total_items": "Itens Totais",
|
||||
"total_labels": "Etiquetas Totais",
|
||||
"total_locations": "Locais Totais",
|
||||
"total_value": "Valor Total"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Registro Desativado",
|
||||
"dont_join_group": "Não quer participar de um grupo?",
|
||||
@@ -136,71 +80,32 @@
|
||||
},
|
||||
"items": {
|
||||
"add": "Adicionar",
|
||||
"advanced": "Avançada",
|
||||
"archived": "Arquivado",
|
||||
"asset_id": "ID do Ativo",
|
||||
"attachment": "Anexo",
|
||||
"attachments": "Anexos",
|
||||
"changes_persisted_immediately": "Alterações nos anexos serão salvas imediatamente",
|
||||
"created_at": "Criado em",
|
||||
"custom_fields": "Campos Personalizados",
|
||||
"description": "Descrição",
|
||||
"details": "Detalhes",
|
||||
"drag_and_drop": "Arraste e solte os arquivos aqui ou clique para selecionar os arquivos",
|
||||
"edit_details": "Detalhes da Edição",
|
||||
"field_selector": "Seletor de Campo",
|
||||
"field_value": "Valor do Campo",
|
||||
"first": "Primeira",
|
||||
"first": "Primeiro",
|
||||
"include_archive": "Incluir itens arquivados",
|
||||
"insured": "Segurado",
|
||||
"last": "Última",
|
||||
"lifetime_warranty": "Garantia Vitalícia",
|
||||
"location": "Local",
|
||||
"manual": "Manual",
|
||||
"manuals": "Manuais",
|
||||
"manufacturer": "Fabricante",
|
||||
"model_number": "Modelo",
|
||||
"name": "Nome",
|
||||
"last": "Último",
|
||||
"negate_labels": "Negar os rótulos selecionados",
|
||||
"next_page": "Próxima página",
|
||||
"no_results": "Nenhum Item Encontrado",
|
||||
"notes": "Anotações",
|
||||
"options": "Opções",
|
||||
"order_by": "Ordenar Por",
|
||||
"pages": "Página { page } de { totalPages }",
|
||||
"parent_item": "Item Pai",
|
||||
"photo": "Foto",
|
||||
"photos": "Fotos",
|
||||
"prev_page": "Página anterior",
|
||||
"purchase_date": "Comprado Em",
|
||||
"purchase_details": "Detalhes da Compra",
|
||||
"purchase_price": "Preço da Compra",
|
||||
"purchased_from": "Comprado De",
|
||||
"quantity": "Quantidade",
|
||||
"query_id": "Consultando o número de ID do ativo: { id }",
|
||||
"receipt": "Recibo",
|
||||
"receipts": "Recibos",
|
||||
"reset_search": "Reiniciar Pesquisa",
|
||||
"results": "{ total } Resultados",
|
||||
"serial_number": "Número Serial",
|
||||
"show_advanced_view_options": "Exibir Opções de Visualização Avançada",
|
||||
"sold_at": "Vendido Em",
|
||||
"sold_details": "Detalhes da Venda",
|
||||
"sold_price": "Preço da Venda",
|
||||
"sold_to": "Vendido Para",
|
||||
"tip_1": "Os filtros de local e etiqueta usam o operador \"OR\". Se você selecionar mais de um, somente um será\nnecessário para obter um resultado.",
|
||||
"tip_2": "As pesquisas comprefixo '#'' buscam um ID de ativo (exemplo '#000-001')",
|
||||
"tip_3": "Os filtros de local e etiqueta usam o operador \"OR\". Se você selecionar mais de um, somente um será\nnecessário para obter um resultado.",
|
||||
"tips": "Dicas",
|
||||
"tips_sub": "Dicas de pesquisa",
|
||||
"updated_at": "Atualizado em",
|
||||
"warranty": "Garantia",
|
||||
"warranty_details": "Detalhes da Garantia",
|
||||
"warranty_expires": "Garantia Expira Em"
|
||||
"updated_at": "Atualizado em"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Nenhuma etiqueta encontrada",
|
||||
"update_label": "Atualizar Etiqueta"
|
||||
"no_results": "Nenhuma etiqueta encontrada"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Catalão",
|
||||
@@ -210,30 +115,20 @@
|
||||
"fr": "Francês",
|
||||
"hu": "Húngaro",
|
||||
"it": "Italiano",
|
||||
"ja-JP": "Japonês",
|
||||
"nl": "Holandês",
|
||||
"pl": "Polonês",
|
||||
"pt-BR": "Português (Brasil)",
|
||||
"pt-PT": "Português (Portugal)",
|
||||
"ru": "Russo",
|
||||
"sl": "Esloveno",
|
||||
"sv": "Sueco",
|
||||
"tr": "Turco",
|
||||
"uk-UA": "Ucraniano",
|
||||
"zh-CN": "Chinês (Simplificado)",
|
||||
"zh-HK": "Chinês (Hong Kong)",
|
||||
"zh-MO": "Chinês (Macau)",
|
||||
"zh-TW": "Chinês (Tradicional)"
|
||||
},
|
||||
"languages.da-DK": "Dinamarquês",
|
||||
"languages.fi.FI": "Finlandês",
|
||||
"languages.ro-RO": "Romeno",
|
||||
"languages.sk-SK": "Eslovaco",
|
||||
"locations": {
|
||||
"child_locations": "Locais Filhos",
|
||||
"collapse_tree": "Ocultar Árvore",
|
||||
"no_results": "Nenhum local encontrado",
|
||||
"update_location": "Atualizar Local"
|
||||
"no_results": "Nenhum local encontrado"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
@@ -271,9 +166,6 @@
|
||||
"total_entries": "Total de Entradas"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Item / Ativo",
|
||||
"create_label": "Etiqueta",
|
||||
"create_location": "Local",
|
||||
"home": "Início",
|
||||
"locations": "Locais",
|
||||
"maintenance": "Manutenção",
|
||||
@@ -290,7 +182,6 @@
|
||||
"delete_account_sub": "Excluir sua conta e todos os dados associados. Essa ação não pode ser desfeita.",
|
||||
"display_header": "{ currentValue, select, true {Ocultar cabeçalho} false {Mostrar cabeçalho} other {Não encontrado}}",
|
||||
"enabled": "Ativado",
|
||||
"example": "Exemplo",
|
||||
"gen_invite": "Gerar link de convite",
|
||||
"group_settings": "Definições do grupo",
|
||||
"group_settings_sub": "Configurações de Grupo Compartilhado. É possível que tenha que recarregar a página para que alguns ajustes sejam aplicados.",
|
||||
|
||||
@@ -2,37 +2,11 @@
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Comportamentul pentru importuri cu import_refs existente s-a schimbat. Dacă un import_ref este prezent în fișierul CSV,\nobiectul v-a fi actualizat cu valorile din fișierul CSV.",
|
||||
"description": "Importă un fișier CSV care conține toate obiectele, etichetele și locațiile tale. \nCitește documentația pentru mai multe informații privind format-ul necesar.",
|
||||
"title": "Importă fișier CSV",
|
||||
"upload": "Încarcă"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "{0} în urmă",
|
||||
"days": "zile",
|
||||
"hour": "oră",
|
||||
"hours": "ore",
|
||||
"in": "în {0}",
|
||||
"just-now": "chiar acum",
|
||||
"last-month": "luna trecută",
|
||||
"last-week": "săptămâna trecută",
|
||||
"last-year": "anul trecut",
|
||||
"minute": "minut",
|
||||
"minutes": "minute",
|
||||
"months": "luni",
|
||||
"next-month": "luna următoare",
|
||||
"next-week": "săptămâna viitoare",
|
||||
"next-year": "anul acesta",
|
||||
"second": "secundă",
|
||||
"seconds": "secunde",
|
||||
"tomorrow": "Mâine",
|
||||
"week": "săptămâna",
|
||||
"weeks": "săptămâni",
|
||||
"years": "ani",
|
||||
"yesterday": "ieri"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "URL Pagină"
|
||||
},
|
||||
@@ -42,8 +16,6 @@
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Descriere articol",
|
||||
"item_name": "Denumire articol",
|
||||
"photo_button": "Imagine 📷",
|
||||
"title": "Crează articol"
|
||||
},
|
||||
@@ -53,45 +25,29 @@
|
||||
"items": "Articole",
|
||||
"no_items": "Nu există articole pentru afișare",
|
||||
"table": "Tabel"
|
||||
},
|
||||
"table": {
|
||||
"page": "Pagină",
|
||||
"rows_per_page": "Rânduri pe pagină"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Descrierea etichetei",
|
||||
"label_name": "Nume eticheta",
|
||||
"title": "Crează Etichetă"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Descriere locatie",
|
||||
"location_name": "Nume locație",
|
||||
"title": "Crează Locație"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Locație Părinte"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Nu există locații disponibile. Adaugă o locație nouă folosind butonul\n`<`span class=\"link-primary\"`>`Crează`<`/span`>` din bara de navigație."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Adaugă",
|
||||
"build": "Build: { build }",
|
||||
"confirm": "Confirmă",
|
||||
"create": "Crează",
|
||||
"create_and_add": "Crează și Adaugă încă un articol",
|
||||
"created": "Creat",
|
||||
"delete": "Șterge",
|
||||
"details": "Detalii",
|
||||
"duplicate": "Duplicat",
|
||||
"edit": "Redactare",
|
||||
"email": "Adresă de email",
|
||||
"follow_dev": "Urmărește developer-ul",
|
||||
"github": "Proiect GitHub",
|
||||
@@ -99,29 +55,15 @@
|
||||
"join_discord": "Vino pe Discord",
|
||||
"labels": "Etichete",
|
||||
"locations": "Locații",
|
||||
"maintenance": "Mentenanță",
|
||||
"name": "Nume",
|
||||
"password": "Parolă",
|
||||
"read_docs": "Citește documentația",
|
||||
"save": "Salvare",
|
||||
"search": "Caută",
|
||||
"sign_out": "Ieșire",
|
||||
"submit": "Trimite",
|
||||
"update": "Actualizare",
|
||||
"value": "Valoare",
|
||||
"version": "Versiune: { version }",
|
||||
"welcome": "Bun venit, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Etichete",
|
||||
"quick_statistics": "Statistici rapide",
|
||||
"recently_added": "Adăugat recent",
|
||||
"storage_locations": "Locații de depozitare",
|
||||
"total_items": "Total articole",
|
||||
"total_labels": "Număr total etichete",
|
||||
"total_locations": "Total locații",
|
||||
"total_value": "Valoare totală"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Înregistrare Dezactivată",
|
||||
"dont_join_group": "Nu vrei sa te alături unui grup?",
|
||||
@@ -136,71 +78,29 @@
|
||||
},
|
||||
"items": {
|
||||
"add": "Adaugă",
|
||||
"advanced": "Avansat",
|
||||
"archived": "Arhivate",
|
||||
"asset_id": "ID activ",
|
||||
"attachment": "Atașament",
|
||||
"attachments": "Fișiere atașate",
|
||||
"changes_persisted_immediately": "Modificările atașamentelor vor fi salvate imediat",
|
||||
"created_at": "Creat la",
|
||||
"custom_fields": "Câmpuri personalizate",
|
||||
"description": "Descriere",
|
||||
"details": "Detalii",
|
||||
"drag_and_drop": "Trageți și plasați fișierele aici sau faceți clic pentru a selecta fișierele",
|
||||
"edit_details": "Editare detalii",
|
||||
"field_selector": "Selector Câmp",
|
||||
"field_value": "Valoare Câmp",
|
||||
"first": "Primul",
|
||||
"include_archive": "Include Articole Arhivate",
|
||||
"insured": "Asigurat",
|
||||
"last": "Ultimul",
|
||||
"lifetime_warranty": "Garanție pe viață",
|
||||
"location": "Locație",
|
||||
"manual": "Manual",
|
||||
"manuals": "Manuale",
|
||||
"manufacturer": "Producător",
|
||||
"model_number": "Număr model",
|
||||
"name": "Nume",
|
||||
"negate_labels": "Neagă Etichetele Selectate",
|
||||
"next_page": "Următoarea Pagină",
|
||||
"no_results": "Nu s-au găsit articole",
|
||||
"notes": "Notițe",
|
||||
"options": "Opțiuni",
|
||||
"order_by": "Ordonează După",
|
||||
"pages": "Pagina { page } din { totalPages }",
|
||||
"parent_item": "Articol Părinte",
|
||||
"photo": "Fotografie",
|
||||
"photos": "Fotografii",
|
||||
"prev_page": "Pagina Anterioară",
|
||||
"purchase_date": "Data achiziției",
|
||||
"purchase_details": "Detalii achiziție",
|
||||
"purchase_price": "Prețul de Achiziție",
|
||||
"purchased_from": "Achiziționat de la",
|
||||
"quantity": "Cantitate",
|
||||
"query_id": "Interogarea numărului de identificare a activului: { id }",
|
||||
"receipt": "Chitanță",
|
||||
"receipts": "Chitanțe",
|
||||
"reset_search": "Resetează Căutare",
|
||||
"results": "{ total } Rezultate",
|
||||
"serial_number": "Număr de serie",
|
||||
"show_advanced_view_options": "Afișează opțiuni avansate",
|
||||
"sold_at": "Vândut la",
|
||||
"sold_details": "Detalii vânzare",
|
||||
"sold_price": "Preț vânzare",
|
||||
"sold_to": "Vândut către",
|
||||
"tip_1": "Filtrele de locație și de etichete folosesc operațiunea \"SAU\". Dacă sunt selectate mai multe,\ndoar unul va fi necesar pentru potrivire.",
|
||||
"tip_2": "Căutările prefixate cu '#' vor efectua o căutare după ID de activ (exemplu '#000-001')",
|
||||
"tip_3": "Filtrele de câmp folosesc operația \"OR\". Dacă sunt selectate mai multe, doar unul va fi necesar\npentru potrivire.",
|
||||
"tips": "Sfaturi",
|
||||
"tips_sub": "Sfaturi Căutare",
|
||||
"updated_at": "Actualizat La",
|
||||
"warranty": "Garanție",
|
||||
"warranty_details": "Detalii Garanție",
|
||||
"warranty_expires": "Garanția expiră"
|
||||
"updated_at": "Actualizat La"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Nu s-au găsit Etichete",
|
||||
"update_label": "Actualizare etichetă"
|
||||
"no_results": "Nu s-au găsit Etichete"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Catalană",
|
||||
@@ -210,30 +110,20 @@
|
||||
"fr": "Franceză",
|
||||
"hu": "Maghiară",
|
||||
"it": "Italiană",
|
||||
"ja-JP": "Japoneză",
|
||||
"nl": "Olandeză",
|
||||
"pl": "Poloneză",
|
||||
"pt-BR": "Portugheză (Brazilia)",
|
||||
"pt-PT": "Portugheză (Portugalia)",
|
||||
"ru": "Rusă",
|
||||
"sl": "Slovenă",
|
||||
"sv": "Suedeză",
|
||||
"tr": "Turcă",
|
||||
"uk-UA": "Ucraininană",
|
||||
"zh-CN": "Chineză (Simplificată)",
|
||||
"zh-HK": "Chineză (Hong Kong)",
|
||||
"zh-MO": "Chineză (Macau)",
|
||||
"zh-TW": "Chineză (Tradițională)"
|
||||
},
|
||||
"languages.da-DK": "Daneză",
|
||||
"languages.fi.FI": "Finlandeză",
|
||||
"languages.ro-RO": "Română",
|
||||
"languages.sk-SK": "Slovacă",
|
||||
"locations": {
|
||||
"child_locations": "Locații copii",
|
||||
"collapse_tree": "Contrage arbore",
|
||||
"no_results": "Nu s-au găsit Locații",
|
||||
"update_location": "Actualizare locație"
|
||||
"no_results": "Nu s-au găsit Locații"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
@@ -271,9 +161,6 @@
|
||||
"total_entries": "Înregistrări Totale"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Articol / Activ",
|
||||
"create_label": "Etichetă",
|
||||
"create_location": "Locație",
|
||||
"home": "Acasă",
|
||||
"locations": "Locații",
|
||||
"maintenance": "Mentenanță",
|
||||
@@ -287,65 +174,38 @@
|
||||
"currency_format": "Format monedă",
|
||||
"current_password": "Parola Actuală",
|
||||
"delete_account": "Șterge Cont",
|
||||
"delete_account_sub": "Ștergeți contul și toate datele asociate acestuia. Această acțiune nu poate fi revocată.",
|
||||
"display_header": "{ currentValue, select, true {Hide Header} false {Show Header} other {Not Hit}}",
|
||||
"enabled": "Activat",
|
||||
"example": "Exemplu",
|
||||
"gen_invite": "Generează Link Invitație",
|
||||
"group_settings": "Setări Grup",
|
||||
"group_settings_sub": "Setări Grup Partajare. Este posibil să fie nevoie să reîncărcați browser-ul pentru aplicarea unor setări.",
|
||||
"inactive": "Inactiv",
|
||||
"language": "Limbă",
|
||||
"new_password": "Parolă Nouă",
|
||||
"no_notifiers": "Niciun notificator configurat",
|
||||
"notifier_modal": "{ type, select, true {Edit} false {Create} other {Other}} Notifier",
|
||||
"notifiers": "Notificatori",
|
||||
"notifiers_sub": "Primiți notificări pentru mementourile de întreținere viitoare",
|
||||
"test": "Test",
|
||||
"theme_settings": "Setări Temă",
|
||||
"theme_settings_sub": "Setările temei sunt stocate în spațiul de stocare local al browserului. Poți schimba tema oricând. Dacă ai \ndificultăți la setarea temei, poți încerca să reîmprospătezi browser-ul.",
|
||||
"update_group": "Actualizare Grup",
|
||||
"update_language": "Actualizare Limbă",
|
||||
"url": "URL",
|
||||
"user_profile": "Profil Utilizator",
|
||||
"user_profile_sub": "Invitați utilizatori și gestionați-vă contul."
|
||||
"user_profile": "Profil Utilizator"
|
||||
},
|
||||
"tools": {
|
||||
"actions": "Acțiuni Inventar",
|
||||
"actions_set": {
|
||||
"ensure_ids": "Garantează ID-urile activelor",
|
||||
"ensure_ids_button": "Garantează ID-urile activelor",
|
||||
"ensure_ids_sub": "Garantează că toate articolele din inventar au un câmp asset_id valid. Acest lucru se face găsind câmpul cu cel mai mare asset_id curent și aplicând următoarea valoare fiecărui articol care nu are câmpul assed_id completat. Acest lucru se face în ordinea dată de câmpul created_at.",
|
||||
"ensure_import_refs": "Garantează Import Refs",
|
||||
"ensure_import_refs_button": "Garantează Import Refs",
|
||||
"ensure_import_refs_sub": "Garantează că toate articolele din inventar au un câmp import_ref valid. Acest lucru se face prin generarea unui șir de 8 caractere aleatoare pentru fiecare articol ce nu are câmp import_ref.",
|
||||
"set_primary_photo": "Setează ca Imagine Principală",
|
||||
"set_primary_photo_button": "Setează ca Imagine Principală",
|
||||
"set_primary_photo_sub": "În versiunea v0.10.0 a Homebox, câmpul de imagine primară a fost adăugat la atașamentele de tip fotografie. Această acțiune va seta câmpul de imagine primară la prima imagine din matricea de atașamente din baza de date, dacă acest lucru nu este facut deja. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'Vezi GitHub PR #576'</a>'",
|
||||
"zero_datetimes": "Zero articol Data Ore",
|
||||
"zero_datetimes_button": "Zero articol Data Ore",
|
||||
"zero_datetimes_sub": "Resetează valoarea de timp pentru toate câmpurile de dată și oră din inventar la începutul datei. Acesta este un fix pentru un bug care a fost introdus la începutul dezvoltării și care a cauzat valoarea timpului să fie stocată cu timpul ceea ce a provocat probleme cu afișarea corectă a câmpurilor de dată. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'Vezi Github Issue #236 pentru mai multe detalii.'</a>'"
|
||||
"set_primary_photo_button": "Setează ca Imagine Principală"
|
||||
},
|
||||
"actions_sub": "Aplicați acțiuni în inventar în bloc. Aceste acțiuni sunt ireversibile. '<b>'Procedați cu atenție.'</b>'",
|
||||
"import_export": "Import/Export",
|
||||
"import_export_set": {
|
||||
"export": "Exportă Inventar",
|
||||
"export_button": "Exportă Inventar",
|
||||
"export_sub": "Exportă formatul CSV standard pentru Homebox. Această acțiune ca exporta toate articolele din inventar.",
|
||||
"import": "Importă Inventar",
|
||||
"import_button": "Importă Inventar",
|
||||
"import_sub": "Importă formatul CSV standard pentru Homebox. Fără o coloana '<code>'HB.import_ref'</code>', '<b>'nu'</b>' se vor suprascrie articole existente în inventar, doar se vor adăuga articole noi. Câmpurile ce au o coloană '<code>'HB.import_ref'</code>' vor fi contopite cu articole existente care au același import_ref, în cazul în care acesta există."
|
||||
"import_button": "Importă Inventar"
|
||||
},
|
||||
"import_export_sub": "Importați și exportați inventarul într-un fișier CSV. Acest lucru este util atunci când se migrează inventarul către o instanță nouă de Homebox.",
|
||||
"reports": "Rapoarte",
|
||||
"reports_set": {
|
||||
"asset_labels": "Etichete de identificare a activului",
|
||||
"asset_labels_button": "Generator de etichete",
|
||||
"asset_labels_sub": "Generează un PDF imprimabil conținând etichete pentru o serie de ID-uri de activ. Acestea nu sunt specifice inventarului tău așadar etichetele se pot imprima din timp și se pot aplica ulterior.",
|
||||
"bill_of_materials": "Lista Materialelor",
|
||||
"bill_of_materials_button": "Generează BOM",
|
||||
"bill_of_materials_sub": "Generează un fișier CSV (Valori separate prin virgulă) care poate fi importat într-un program de foi de calcul. Acesta este un sumar ar inventarului cu informații minimale legate de articole și prețuri."
|
||||
},
|
||||
"reports_sub": "Generați rapoarte diferite pentru inventarul tău."
|
||||
"bill_of_materials_button": "Generează BOM"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
"hour": "час",
|
||||
"hours": "часов",
|
||||
"in": "через {0}",
|
||||
"just-now": "только что",
|
||||
"last-month": "предыдущий месяц",
|
||||
"last-week": "предыдущая неделя",
|
||||
"last-year": "предыдущий год",
|
||||
@@ -62,36 +61,24 @@
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Описание метки",
|
||||
"label_name": "Название метки",
|
||||
"title": "Создать метку"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Описание локации",
|
||||
"location_name": "Название локации",
|
||||
"title": "Создать локацию"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Родительская локация"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Нет доступных локаций. Добавьте новую локацию, \nнажав на кнопку `<`span class=\"link-primary\"`>`Создать`<`/span`>` в навигационном меню."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Добавить",
|
||||
"build": "Сборка: { build }",
|
||||
"confirm": "Подтвердить",
|
||||
"create": "Создать",
|
||||
"create_and_add": "Создать и добавить еще",
|
||||
"created": "Создано",
|
||||
"delete": "Удалить",
|
||||
"details": "Подробнее",
|
||||
"duplicate": "Дублировать",
|
||||
"edit": "Редактировать",
|
||||
"email": "Email",
|
||||
"follow_dev": "Следить за разработчиком",
|
||||
"github": "Github проект",
|
||||
@@ -99,29 +86,15 @@
|
||||
"join_discord": "Присоединяйтесь к Discord",
|
||||
"labels": "Метки",
|
||||
"locations": "Локации",
|
||||
"maintenance": "Техническое обслуживание и ремонт",
|
||||
"name": "Имя",
|
||||
"password": "Пароль",
|
||||
"read_docs": "Прочитать документацию",
|
||||
"save": "Сохранить",
|
||||
"search": "Поиск",
|
||||
"sign_out": "Выйти",
|
||||
"submit": "Отправить",
|
||||
"update": "Обновить",
|
||||
"value": "Значение",
|
||||
"version": "Версия: { version }",
|
||||
"welcome": "Добро пожаловать, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Метки",
|
||||
"quick_statistics": "Быстрая статистика",
|
||||
"recently_added": "Недавно добавлено",
|
||||
"storage_locations": "Места хранения",
|
||||
"total_items": "Всего элементов",
|
||||
"total_labels": "Всего меток",
|
||||
"total_locations": "Общее количество местоположений",
|
||||
"total_value": "Общая стоимость"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Регистрация отключена",
|
||||
"dont_join_group": "Не хотите ли вступить в группу?",
|
||||
@@ -136,71 +109,32 @@
|
||||
},
|
||||
"items": {
|
||||
"add": "Добавить",
|
||||
"advanced": "Дополнительно",
|
||||
"archived": "В архиве",
|
||||
"asset_id": "Инвентарный ID",
|
||||
"attachment": "Вложение",
|
||||
"attachments": "Вложения",
|
||||
"changes_persisted_immediately": "Изменения во вложениях будут сохранены сразу же",
|
||||
"created_at": "Создано в",
|
||||
"custom_fields": "Настраиваемые поля",
|
||||
"description": "Описание",
|
||||
"details": "Подробнее",
|
||||
"drag_and_drop": "Перетащите файлы сюда или нажмите, чтобы выбрать файлы",
|
||||
"edit_details": "Редактирование деталей",
|
||||
"field_selector": "Поле выбора",
|
||||
"field_value": "Значение поля",
|
||||
"first": "Первый",
|
||||
"include_archive": "Включая архивированные элементы",
|
||||
"insured": "Застраховано",
|
||||
"last": "Последний",
|
||||
"lifetime_warranty": "Гарантия на весь срок эксплуатации",
|
||||
"location": "Местоположение",
|
||||
"manual": "Руководство по эксплуатации",
|
||||
"manuals": "Документация",
|
||||
"manufacturer": "Производитель",
|
||||
"model_number": "Номер модели",
|
||||
"name": "Название",
|
||||
"negate_labels": "Снять выбранные ярлыки",
|
||||
"next_page": "Следующая страница",
|
||||
"no_results": "Элементы не найдены",
|
||||
"notes": "Заметки",
|
||||
"options": "Параметры",
|
||||
"order_by": "Сортировка по",
|
||||
"pages": "Страница {page} из {totalPages}",
|
||||
"parent_item": "Родительский элемент",
|
||||
"photo": "Фото",
|
||||
"photos": "Фотографии",
|
||||
"prev_page": "Предыдущая страница",
|
||||
"purchase_date": "Дата покупки",
|
||||
"purchase_details": "Детали покупки",
|
||||
"purchase_price": "Стоимость покупки",
|
||||
"purchased_from": "Продавец",
|
||||
"quantity": "Количество",
|
||||
"query_id": "Запрос идентификационного номера актива: { id }",
|
||||
"receipt": "Квитанция",
|
||||
"receipts": "Квитанции",
|
||||
"reset_search": "Сбросить поиск",
|
||||
"results": "{ total } Результатов",
|
||||
"serial_number": "Серийный номер",
|
||||
"show_advanced_view_options": "Показать дополнительные параметры",
|
||||
"sold_at": "Место продажи",
|
||||
"sold_details": "Детали продажи",
|
||||
"sold_price": "Цена продажи",
|
||||
"sold_to": "Покупатель",
|
||||
"tip_1": "При фильтрации по локации и по ярлыкам используется логический оператор «ИЛИ». Если выбрано несколько фильтров, то для срабатывания\n требуется лишь одно совпадение.",
|
||||
"tip_2": "Поисковые запросы с префиксом \"#\" должны включать в себя ID актива (прим. '#000-001')",
|
||||
"tip_3": "Фильтры по полю используют операцию «ИЛИ». Если выбрано несколько фильтров, для совпадения\n требуется только один.",
|
||||
"tips": "Подсказки",
|
||||
"tips_sub": "Поисковые подсказки",
|
||||
"updated_at": "Обновлено в",
|
||||
"warranty": "Гарантия",
|
||||
"warranty_details": "Гарантийная информация",
|
||||
"warranty_expires": "Срок гарантии истекает"
|
||||
"updated_at": "Обновлено в"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Метки не найдены",
|
||||
"update_label": "Обновить метку"
|
||||
"no_results": "Метки не найдены"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Каталанский",
|
||||
@@ -210,30 +144,20 @@
|
||||
"fr": "французский",
|
||||
"hu": "Венгерский",
|
||||
"it": "Итальянский",
|
||||
"ja-JP": "Японский",
|
||||
"nl": "Голландский",
|
||||
"pl": "Польский",
|
||||
"pt-BR": "Португальский (Бразилия)",
|
||||
"pt-PT": "Португальский (Португалия)",
|
||||
"ru": "Русский",
|
||||
"sl": "Словенский",
|
||||
"sv": "Шведский",
|
||||
"tr": "Турецкий",
|
||||
"uk-UA": "Украинский",
|
||||
"zh-CN": "Китайский (упрощенный)",
|
||||
"zh-HK": "Китайский (Гонконг)",
|
||||
"zh-MO": "Китайский (Макао)",
|
||||
"zh-TW": "китайский (традиционный)"
|
||||
},
|
||||
"languages.da-DK": "Датский (Дания)",
|
||||
"languages.fi.FI": "Финский",
|
||||
"languages.ro-RO": "Румынский",
|
||||
"languages.sk-SK": "Словацкий",
|
||||
"locations": {
|
||||
"child_locations": "Вложенные локации",
|
||||
"collapse_tree": "Свернуть всё дерево",
|
||||
"no_results": "Локаций не найдено",
|
||||
"update_location": "Обновить локацию"
|
||||
"no_results": "Локаций не найдено"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
@@ -271,9 +195,6 @@
|
||||
"total_entries": "Всего записей"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Элемент",
|
||||
"create_label": "Метка",
|
||||
"create_location": "Местоположение",
|
||||
"home": "Главная",
|
||||
"locations": "Локации",
|
||||
"maintenance": "Техническое обслуживание и ремонт",
|
||||
@@ -290,7 +211,6 @@
|
||||
"delete_account_sub": "Удалить свой аккаунт и все связанные с ним данные. Это действие невозможно отменить.",
|
||||
"display_header": "{ currentValue, select, true {Скрыть заголовок} false {Показать заголовок} other {Нет результатов}}",
|
||||
"enabled": "Активен",
|
||||
"example": "Пример",
|
||||
"gen_invite": "Сгенерировать ссылку-приглашение",
|
||||
"group_settings": "Настройки группы",
|
||||
"group_settings_sub": "Настройки общей группы. Для применения изменений возможно потребуется перезагрузить страницу.",
|
||||
|
||||
@@ -225,10 +225,6 @@
|
||||
"zh-MO": "Čínština (Macao)",
|
||||
"zh-TW": "Číština (tradičná)"
|
||||
},
|
||||
"languages.da-DK": "Dánsko",
|
||||
"languages.fi.FI": "Finsko",
|
||||
"languages.ro-RO": "Rumunsko",
|
||||
"languages.sk-SK": "Slovenčina",
|
||||
"locations": {
|
||||
"child_locations": "Umiestnenie dieťaťa",
|
||||
"collapse_tree": "Zbaliť strom",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user