Compare commits

..

1 Commits

Author SHA1 Message Date
github-actions[bot] 04b074454a chore: bump version to v0.8.31 2026-06-01 10:33:11 +00:00
5 changed files with 145 additions and 146 deletions
+89 -14
View File
@@ -15,6 +15,15 @@ on:
- patch
- minor
- major
- development
push_dev:
description: "If true, push the :dev image to GHCR for development releases"
required: false
default: "false"
type: choice
options:
- "true"
- "false"
permissions:
contents: write
@@ -39,12 +48,13 @@ jobs:
EVENT_NAME: ${{ github.event_name }}
REF_NAME: ${{ github.ref_name }}
BUMP_TYPE: ${{ github.event.inputs.bump || 'patch' }}
PUSH_DEV: ${{ github.event.inputs.push_dev || 'false' }}
run: |
if [ "$EVENT_NAME" = "push" ] && [ -n "$REF_NAME" ]; then
TAG="$REF_NAME"
else
# Fetch latest release tag via GitHub API (fall back to v0.8.31)
latest_tag="v0.8.31"
# Fetch latest release tag via GitHub API (fall back to v3.0.0)
latest_tag="v3.0.0"
if meta_json=$(curl -fsSL -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" "https://api.github.com/repos/$REPO/releases/latest" 2>/dev/null); then
tag_name=$(printf "%s" "$meta_json" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)
if [ -n "$tag_name" ]; then
@@ -57,7 +67,7 @@ jobs:
minor=${BASH_REMATCH[2]}
patch=${BASH_REMATCH[3]}
else
major=0; minor=8; patch=31
major=3; minor=0; patch=0
fi
# Bump strategy: major / minor / patch
@@ -68,28 +78,30 @@ jobs:
else
patch=$((patch + 1))
fi
# Zusammenbau des Tags für den manuellen Run
TAG="v${major}.${minor}.${patch}"
if [ "${BUMP_TYPE:-}" = "development" ]; then
TAG="v${major}.${minor}.${patch}-dev"
else
TAG="v${major}.${minor}.${patch}"
fi
fi
# Validierung des erzeugten oder übergebenen Tags
if ! echo "$TAG" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+(-dev(\.[0-9]+)?)?$'; then
echo "Error: tag '$TAG' is not valid semver (vX.Y.Z)"
echo "Error: tag '$TAG' is not valid semver (vX.Y.Z or vX.Y.Z-dev)"
exit 1
fi
git fetch --tags --force
LATEST_TAG="$(git tag -l 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n1)"
if [ -z "$LATEST_TAG" ]; then
LATEST_TAG="v0.8.31"
LATEST_TAG="v3.0.0"
fi
TAG_MAJOR="${TAG#v}"
TAG_MAJOR="${TAG_MAJOR%%.*}"
LATEST_MAJOR="$(echo "$LATEST_TAG" | grep -Eo '^v[0-9]+' | tr -d 'v')"
if [ -z "$LATEST_MAJOR" ]; then
LATEST_MAJOR="0"
LATEST_MAJOR="3"
fi
# If not explicitly bumping major, disallow changing major version
@@ -111,6 +123,33 @@ jobs:
IMAGE="ghcr.io/aiirondev/legendary-octo-garbanzo:${TAG}"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "image=$IMAGE" >> "$GITHUB_OUTPUT"
if [ "${BUMP_TYPE:-}" = "development" ]; then
echo "is_development=true" >> "$GITHUB_OUTPUT"
else
echo "is_development=false" >> "$GITHUB_OUTPUT"
fi
if [ "${BUMP_TYPE:-}" = "development" ] && [ "${PUSH_DEV:-}" = "true" ]; then
echo "push_dev=true" >> "$GITHUB_OUTPUT"
else
echo "push_dev=false" >> "$GITHUB_OUTPUT"
fi
- name: Update .release-version file
run: |
echo "${{ steps.meta.outputs.tag }}" > .release-version
cat .release-version
- name: Create and push tag for manual releases
if: github.event_name == 'workflow_dispatch'
run: |
TAG="${{ steps.meta.outputs.tag }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .release-version
git commit -m "chore: bump version to $TAG" || true
git tag "$TAG"
git push origin "$TAG"
git push origin HEAD:${{ github.ref_name }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -123,16 +162,26 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push release image
if: steps.meta.outputs.is_development != 'true'
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
load: true # Lädt das Image in den lokalen Docker-Daemon für den 'docker save' Schritt
tags: |
${{ steps.meta.outputs.image }}
ghcr.io/aiirondev/legendary-octo-garbanzo:latest
- name: Build and push development image (:dev)
if: steps.meta.outputs.is_development == 'true' && steps.meta.outputs.push_dev == 'true'
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: |
ghcr.io/aiirondev/legendary-octo-garbanzo:dev
- name: Build local image tar for offline deploy
run: |
set -euo pipefail
@@ -155,17 +204,30 @@ jobs:
docker build -t "$IMG" .
docker save "$IMG" | gzip > "inventarsystem-image-${TAG}.tar.gz"
# development tar omitted: dev releases will be versioned (vX.Y.Z-dev) and handled by update.sh using the tag
- name: Commit .release-version for tag pushes
if: github.event_name == 'push'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if ! git diff --quiet .release-version; then
git add .release-version
git commit -m "chore: update version to ${{ steps.meta.outputs.tag }}"
git push origin HEAD:${{ github.ref_name }}
fi
- name: Create release-only docker bundle
run: |
mkdir -p release-bundle
cat > release-bundle/docker-compose.yml <<EOF
services:
app:
image: \${INVENTAR_APP_IMAGE:-ghcr.io/aiirondev/legendary-octo-garbanzo:${{ steps.meta.outputs.tag }}}
image: ${INVENTAR_APP_IMAGE:-ghcr.io/aiirondev/legendary-octo-garbanzo:${{ steps.meta.outputs.tag }}}
container_name: inventarsystem-app
restart: unless-stopped
ports:
- "\${INVENTAR_HTTP_PORT:-10000}:8000"
- "${INVENTAR_HTTP_PORT:-10000}:8000"
depends_on:
- mongodb
- redis
@@ -238,6 +300,17 @@ jobs:
fi
done
cat > release-bundle/DEVELOPMENT.md <<EOF
This is a development prerelease bundle for tag: ${{ steps.meta.outputs.tag }}
This prerelease is intentionally separate from normal releases and will not be used by default.
To install this prerelease on a target host run:
./update.sh ${{ steps.meta.outputs.tag }}
EOF
# Make any shipped scripts executable
find release-bundle -maxdepth 1 -type f -name '*.sh' -exec chmod +x {} \; || true
tar -czf inventarsystem-docker-bundle.tar.gz -C release-bundle .
@@ -246,8 +319,10 @@ jobs:
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.meta.outputs.tag }}
prerelease: ${{ steps.meta.outputs.is_development }}
files: |
inventarsystem-docker-bundle.tar.gz
inventarsystem-image-${{ steps.meta.outputs.tag }}.tar.gz
inventarsystem-image-dev.tar.gz
fail_on_unmatched_files: false
generate_release_notes: true
generate_release_notes: true
+1 -1
View File
@@ -1 +1 @@
v0.8.31.1
v0.8.31
-25
View File
@@ -119,21 +119,6 @@ class HybridScanner {
// Make video element visible (ensure it's not hidden by display: none)
this.state.videoElement.style.display = 'block';
// Ensure autoplay works on mobile by muting and setting playsInline
try {
this.state.videoElement.muted = true;
this.state.videoElement.autoplay = true;
this.state.videoElement.playsInline = true;
// Some browsers require explicit play() after setting srcObject
const p = this.state.videoElement.play();
if (p && p.then) {
p.catch(() => {
// ignore play promise rejection (user gesture required on some browsers)
});
}
} catch (e) {
// ignore
}
// Initialize ZXing reader
const hints = new Map();
@@ -173,16 +158,6 @@ class HybridScanner {
this.state.videoElement.style.display = 'none';
}
// Reset ZXing reader to stop any internal loops
try {
if (this.state.reader && typeof this.state.reader.reset === 'function') {
this.state.reader.reset();
}
} catch (e) {
// ignore
}
this.state.reader = null;
this.removeKeyboardInput();
}
+1 -106
View File
@@ -564,29 +564,6 @@ document.addEventListener('DOMContentLoaded', function() {
});
initMobileWindowedLibraryLoading();
// On mobile, make tapping an item open details for easier access (tap target larger)
function enableMobileTapToDetails() {
if (!isMobileViewport()) return;
document.querySelectorAll('.library-item').forEach(item => {
item.addEventListener('click', function(e) {
// Ignore clicks on buttons/links inside the card
const tag = e.target.tagName.toLowerCase();
if (tag === 'button' || tag === 'a' || e.target.closest('.action-button')) return;
const itemId = this.dataset.itemId;
if (!itemId) return;
fetch(`/get_item_details/${itemId}`)
.then(r => r.json())
.then(data => {
if (data.success) {
displayLibraryItemDetail(data.item);
document.getElementById('detailModal').style.display = 'flex';
}
});
}, { passive: true });
});
}
enableMobileTapToDetails();
});
function displayLibraryItemDetail(item) {
@@ -597,7 +574,7 @@ function displayLibraryItemDetail(item) {
modalBody.innerHTML = `
<h2>${item.Name}</h2>
<div class="detail-content">
${item.Image ? `<img src="/uploads/${item.Image}" alt="${item.Name}" class="detail-image">` : ''}
${item.Image ? `<img src="/uploads/${item.Image}" alt="${item.Name}" style="max-width: 200px; margin-bottom: 20px;">` : ''}
<p><strong>Autor:</strong> ${item.Author || '—'}</p>
<p><strong>ISBN:</strong> ${item.ISBN || '—'}</p>
<p><strong>Typ:</strong> ${item.ItemType || 'Medium'}</p>
@@ -814,37 +791,6 @@ function onScanError(error) {
color: #b3261e;
}
/* Mobile: simplify list entries - show only title */
@media (max-width: 900px) {
.library-item .item-author,
.library-item .item-isbn,
.table-cell.author-cell,
.table-cell.isbn-cell {
display: none !important;
}
/* Make title more prominent and full-width */
.library-item .item-details {
display: block;
width: calc(100% - 140px);
box-sizing: border-box;
}
.library-item .item-name {
font-size: 1.05rem;
margin: 0 0 6px 0;
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.library-item .item-image-wrapper {
width: 100px;
height: 130px;
}
}
/* Mobile: allow horizontal scrolling for table-mode views */
@media (max-width: 900px) {
.library-table-wrapper {
@@ -986,56 +932,5 @@ function onScanError(error) {
font-size: 0.85em;
}
}
/* Modal styles - responsive for mobile */
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0,0,0,0.5);
z-index: 2000;
padding: 16px;
box-sizing: border-box;
}
.modal-content {
background: #fff;
border-radius: 10px;
width: 100%;
max-width: 640px;
max-height: 90vh;
overflow-y: auto;
box-sizing: border-box;
padding: 16px;
position: relative;
}
.modal-close {
background: transparent;
border: none;
font-size: 1.1rem;
position: absolute;
right: 20px;
top: 18px;
cursor: pointer;
}
.modal-body img {
max-width: 100%;
height: auto;
display: block;
margin-bottom: 12px;
}
.modal-body p { margin: 6px 0; }
@media (max-width: 420px) {
.modal-content { padding: 12px; }
}
</style>
{% endblock %}
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
"""
Small debug script to check tenant-aware lookup for an appointment id.
Usage: ./tools/debug_get_appointment.py <appointment_id> [tenant]
"""
import sys
from bson.objectid import ObjectId
from Web.modules.database.settings import MongoClient, MONGODB_HOST, MONGODB_PORT, MONGODB_DB
import Web.modules.database.termine as termine
def main():
if len(sys.argv) < 2:
print("Usage: debug_get_appointment.py <appointment_id> [tenant]")
sys.exit(2)
aid = sys.argv[1]
tenant = sys.argv[2] if len(sys.argv) > 2 else None
if tenant:
print(f"Looking up appointment {aid} for tenant {tenant}")
else:
print(f"Looking up appointment {aid} for default tenant")
try:
# Use the module helper directly
item = termine.get_item(aid)
if item:
print('Found with termini.get_item:')
print(item)
else:
print('termin.get_item returned None')
# Try explicit MongoClient + tenant DB resolution
client = MongoClient(MONGODB_HOST, MONGODB_PORT)
try:
from Web.tenant import TenantContext, get_tenant_db
if tenant:
ctx = TenantContext()
ctx.tenant_id = tenant
db = ctx.get_database(client)
else:
db = get_tenant_db(client) if 'get_tenant_db' in dir() else client[MONGODB_DB]
doc = db['appointments'].find_one({'_id': ObjectId(aid)})
print('Direct DB find_one returned:')
print(doc)
finally:
client.close()
except Exception as e:
print('Error during debug lookup:', e)
if __name__ == '__main__':
main()