From 232d2270c33a407f944df222313e2f9aaff58f84 Mon Sep 17 00:00:00 2001 From: "Adrian A. Baumann" Date: Sun, 4 Jan 2026 11:10:12 +0100 Subject: [PATCH] Some bugs (box-management didn't work); Tags now on search and in box content --- argocd/deployment.yaml | 4 ++-- boxes/templates/boxes/box_detail.html | 10 ++++++++++ boxes/templates/boxes/search.html | 11 +++++++++-- boxes/tests.py | 6 +++--- boxes/views.py | 13 ++++++++++--- data-loader/preload.sqlite3 | Bin 266240 -> 266240 bytes labhelper/urls.py | 6 ++++++ 7 files changed, 40 insertions(+), 10 deletions(-) diff --git a/argocd/deployment.yaml b/argocd/deployment.yaml index 5c7896f..4867ea6 100644 --- a/argocd/deployment.yaml +++ b/argocd/deployment.yaml @@ -18,7 +18,7 @@ spec: fsGroupChangePolicy: "OnRootMismatch" initContainers: - name: loader - image: git.baumann.gr/adebaumann/labhelper-data-loader:0.013 + image: git.baumann.gr/adebaumann/labhelper-data-loader:0.014 securityContext: runAsUser: 0 command: [ "sh","-c","if [ ! -f /data/db.sqlite3 ] || [ ! -s /data/db.sqlite3 ]; then cp preload/preload.sqlite3 /data/db.sqlite3 && echo 'Database copied from preload'; else echo 'Existing database preserved'; fi" ] @@ -27,7 +27,7 @@ spec: mountPath: /data containers: - name: web - image: git.baumann.gr/adebaumann/labhelper:0.048 + image: git.baumann.gr/adebaumann/labhelper:0.049 imagePullPolicy: Always ports: - containerPort: 8000 diff --git a/boxes/templates/boxes/box_detail.html b/boxes/templates/boxes/box_detail.html index d0095e2..d55d41e 100644 --- a/boxes/templates/boxes/box_detail.html +++ b/boxes/templates/boxes/box_detail.html @@ -37,6 +37,7 @@ Picture Name + Tags Description @@ -55,6 +56,15 @@ {{ thing.name }} + + {% if thing.tags.all %} + {% for tag in thing.tags.all %} + {{ tag.name }} + {% endfor %} + {% else %} + - + {% endif %} + {{ thing.description|default:"-" }} {% endfor %} diff --git a/boxes/templates/boxes/search.html b/boxes/templates/boxes/search.html index e0b66c4..b831c53 100644 --- a/boxes/templates/boxes/search.html +++ b/boxes/templates/boxes/search.html @@ -29,7 +29,7 @@ Name - Type + Tags Box Description @@ -85,9 +85,16 @@ function performSearch(query) { const row = document.createElement('tr'); row.style.borderBottom = '1px solid #e0e0e0'; row.style.transition = 'background 0.2s'; + + let tagsHtml = thing.tags.length > 0 + ? thing.tags.map(tag => + '' + escapeHtml(tag.name) + '' + ).join('') + : '-'; + row.innerHTML = '' + escapeHtml(thing.name) + '' + - '' + escapeHtml(thing.type) + '' + + '' + tagsHtml + '' + '' + escapeHtml(thing.box) + '' + '' + escapeHtml(thing.description) + ''; diff --git a/boxes/tests.py b/boxes/tests.py index 8b1b255..7c32a3b 100644 --- a/boxes/tests.py +++ b/boxes/tests.py @@ -706,12 +706,12 @@ class SearchApiTests(AuthTestCase): results = response.json()['results'] self.assertEqual(len(results), 50) - def test_search_api_includes_type_and_box(self): - """Search API results should include type and box info.""" + def test_search_api_includes_tags_and_box(self): + """Search API results should include tags and box info.""" response = self.client.get('/search/api/?q=ard') self.assertEqual(response.status_code, 200) results = response.json()['results'] - self.assertEqual(results[0]['type'], 'Electronics') + self.assertEqual(results[0]['tags'], []) self.assertEqual(results[0]['box'], 'BOX001') def test_search_api_requires_login(self): diff --git a/boxes/views.py b/boxes/views.py index b283a25..3f2a682 100644 --- a/boxes/views.py +++ b/boxes/views.py @@ -40,7 +40,7 @@ def index(request): def box_detail(request, box_id): """Display contents of a box.""" box = get_object_or_404(Box, pk=box_id) - things = box.things.all() + things = box.things.prefetch_related('tags').all() return render(request, 'boxes/box_detail.html', { 'box': box, 'things': things, @@ -179,7 +179,7 @@ def search_api(request): things = Thing.objects.filter( Q(tags__facet__name__icontains=facet_name) & Q(tags__name__icontains=tag_name) - ).prefetch_related('files', 'links').select_related('box').distinct()[:50] + ).prefetch_related('files', 'links', 'tags').select_related('box').distinct()[:50] else: # Normal search things = Thing.objects.filter( @@ -191,7 +191,7 @@ def search_api(request): Q(links__url__icontains=query) | Q(tags__name__icontains=query) | Q(tags__facet__name__icontains=query) - ).prefetch_related('files', 'links').select_related('box').distinct()[:50] + ).prefetch_related('files', 'links', 'tags').select_related('box').distinct()[:50] results = [ { @@ -199,6 +199,13 @@ def search_api(request): 'name': thing.name, 'box': thing.box.id, 'description': thing.description[:100] if thing.description else '', + 'tags': [ + { + 'name': tag.name, + 'color': tag.facet.color, + } + for tag in thing.tags.all() + ], 'files': [ { 'title': f.title, diff --git a/data-loader/preload.sqlite3 b/data-loader/preload.sqlite3 index 12b932d1390af92e23eaac508eff0d5498231543..cd70261b5ab44b5bae3c172a9bd5d06684450b9b 100644 GIT binary patch delta 4402 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 N9xhz0pbGx1{SW%(@+|-W delta 2235 zcmaKte{35?7RPsXoL$?yJI{{SZqmfbCI%8HY3wvONomuj`9X>lN)xB}ASAJqO_P!| zxq3;1uDba6qbmQLJ{PS>V%+$ zn;oZIbbp*=z3=+X?Ay=0nRzdr@uV}Jxf1mHvC>xb`q{x3Hdg!fB3y%#lQU*&z#1Lf zzjwe&>`iTfAP%kd_RV{1??>|d!?htaF+WfnK!>x_wR2(VjsTC4J6Uh~pQO4|R0XZY z71T7Rt3|5|*F|f>k(zLw5oy@Gsd00-abrWYDY_|~y?63cqfmw}0dB%Y_&pp23kIQ! zMQMO4uPg~cgiy>(S;mgZnc?B#LP-+JnX6|aF+RTPo3~ER;SjkrFJ~G&PzE|U$sO`7 z`J8-6E@dOeZ^)Cb5MGB`Te{ooWLM?tV?jEOsM`=roy5@gYCn)4 z*+K)F;~w0F=%riO$c@y9Cq(Sk{z~PrcrP10rBQFQ=*xYvRV=H-j}n2(gW~aQoiVKO z1##pj?ye%fcIACJW54(rk_186qfjbOi8P?DS3PQh@`LiV@~Lt~xu7g6rxeP*bJI=f zuf+Y8t|5ouN6BZ$pV6I3hu}ja=0ROaID}%9VrPEb)N@sb#E(;(OQ2eS?_dSKgzK;b ze}Z$c2&W+fb8rNH3m-rl-iH~Of>D;jI6Tf0xE&fH4Am@!UlBvv;t&veyhD1J>uzZ? z*Pzs7YfqAP{v`flAYlKAZTp&iY*yrfu{ z1fQ>@c(?W3FRkZ7jbZblCNrNJnr_DXq{iq_G7_OH&A6?iT$6-#>q>$0O*6m71+-=s7vY{{6YZSEPtV4;1!M=S zRq=j*UgLUR_xSP}D9mfGmusvj!nLn{L*8FY@>-?k)l~DkU2(HLErEUk7T`5_1NOl% z^uvoRm(Rl?md`21_|bZJ8D4_#;TC+&u&=Vy`W{?hsXqrd7_tGh|0oWKJxz4_DDIez z2ke_1_j9Xr>*KbNTd!?n5!?1{;2y%Q#;wZjf2rPwj~LB9MrVKe2Io4*P!2K5ml^9z zjPWXCw1Hk@NK=4s!5gboCm9t>;q*z|(Y=jR^{=7Y!>IzCs+Ut0ajJSwRm-WWIF-q% z^0{L50kNxm11?if20umzGq|Hr^{Fo9w(^Z~O}VVRtNc+pwOS|6V6#$npkk!w&waw> zKt80iN|AIskRR!G`54NTE#RA&S0C**l^1aZeP9tc(|wD0tEY}UNbVyBSx$vQgE4WgS zDd=JYXC2PneUk9dGg^=?E@OSx?y9Wf8P;gRGVE4wBo3Iy{z=OiHpflN95zM{OimcX z2`iCIq)fYe+Qm2=XC3$v&EIBDOd2~abE1XKXOCm-(Xb|s)ac~FAvT|f+-SF+_9rA^ y(^J|y-p1`WjDus=XvB!IZ^lN)QU?1a49jlvJcvDN+$|vaFuV)oiY3QCT>k-=Q6SU+ diff --git a/labhelper/urls.py b/labhelper/urls.py index e420228..09838e3 100644 --- a/labhelper/urls.py +++ b/labhelper/urls.py @@ -22,11 +22,14 @@ from django.contrib.auth import views as auth_views from boxes.views import ( add_box, + add_box_type, add_things, box_detail, box_management, delete_box, + delete_box_type, edit_box, + edit_box_type, index, search, search_api, @@ -38,6 +41,9 @@ urlpatterns = [ path('logout/', auth_views.LogoutView.as_view(), name='logout'), path('', index, name='index'), path('box-management/', box_management, name='box_management'), + path('box-type/add/', add_box_type, name='add_box_type'), + path('box-type//edit/', edit_box_type, name='edit_box_type'), + path('box-type//delete/', delete_box_type, name='delete_box_type'), path('box/add/', add_box, name='add_box'), path('box//edit/', edit_box, name='edit_box'), path('box//delete/', delete_box, name='delete_box'),