38 Commits

Author SHA1 Message Date
8ddac9a56d 🚀 Update push command in CI workflow for release branch
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m40s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Successful in 1m43s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 3m30s
Modified the push command in the CI workflow to correctly target the release branch for deployment. This ensures that changes are pushed to the appropriate branch, enhancing the deployment process.
2026-02-06 20:42:46 -05:00
d1d6d24dbb remove redundant Siteworx CA certificates installation steps from CI workflow
Some checks failed
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m29s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Successful in 1m44s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 3m23s
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 4m51s
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Successful in 6m4s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Failing after 35s
2026-02-06 20:20:25 -05:00
6e908bad17 bump frontend and backend image versions to v0.0.37 2026-02-06 20:10:21 -05:00
f6ed88fd78 ignore ArgoCD paths in push trigger for CI workflow
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m45s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Successful in 1m47s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 3m22s
2026-02-06 20:09:48 -05:00
b122fca494 add checkout step for release branch in CI build process
Some checks failed
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Has been cancelled
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Has been cancelled
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Has been cancelled
2026-02-06 20:09:15 -05:00
1cc6d5ece4 update Go version in Dockerfile to 1.25.6
Some checks failed
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m37s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Successful in 1m53s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 3m26s
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 5m39s
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Successful in 6m41s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Failing after 1m51s
2026-02-06 19:54:37 -05:00
74ea300f80 update Go version and change utilities package import path
Some checks failed
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m46s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Successful in 4m20s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 5m48s
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Failing after 4m31s
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 6m15s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Has been skipped
2026-02-06 19:39:43 -05:00
f8958dfbef add automated build artifact recommit step in CI workflow
Some checks failed
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m30s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Failing after 1m40s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Failing after 1m39s
2026-02-06 19:36:10 -05:00
22e045730f update dependencies and improve bullet manufacturer options deduplication
Some checks failed
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Failing after 1m49s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Failing after 2m6s
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 2m33s
2026-02-06 19:31:10 -05:00
a4edafdd2e update DB_HOST in configmap.yml to use service name
Some checks failed
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 3m32s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Failing after 4m42s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Failing after 5m3s
2026-02-06 19:23:10 -05:00
f8974acab5 update DB_HOST in configmap.yml to use service name
Some checks failed
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Has started running
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Has started running
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Has been cancelled
2026-02-06 19:22:24 -05:00
ac3cd505bf update DB_HOST in configmap.yml to use service name
Some checks are pending
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Has started running
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Has started running
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Has started running
2026-02-06 19:20:20 -05:00
03762a0be7 [create-pull-request] automated change (#10)
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 4m1s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Successful in 7m0s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 7m13s
Co-authored-by: rrise <+rrise@users.noreply.github.com>
Reviewed-on: Siteworxpro/reloading-manager#10
Co-authored-by: Ron Rise <ron@siteworxpro.com>
Co-committed-by: Ron Rise <ron@siteworxpro.com>
2025-06-11 02:04:49 +00:00
0f915ccd82 happy monday _ bleh _ (#9)
Some checks failed
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m23s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Successful in 1m32s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 3m35s
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 6m11s
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Successful in 6m47s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Failing after 53s
Reviewed-on: Siteworxpro/reloading-manager#9
Co-authored-by: Ron Rise <ron@siteworxpro.com>
Co-committed-by: Ron Rise <ron@siteworxpro.com>
2025-06-11 01:43:53 +00:00
dd383b6fb3 fix tpyo (#8)
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 7m28s
🧪 ✨ Unit Tests Workflow / 🧪 🐹 GolangCI-Lint (push) Successful in 7m40s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 10m24s
Reviewed-on: Siteworxpro/reloading-manager#8
Co-authored-by: Ron Rise <ron@siteworxpro.com>
Co-committed-by: Ron Rise <ron@siteworxpro.com>
2025-06-10 15:56:03 +00:00
e484aa7e31 tagging release w.t.f.
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 5m58s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 9m2s
2025-05-16 21:18:03 -04:00
3c60c1b012 [create-pull-request] automated change (#7)
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 6m18s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 9m20s
Co-authored-by: rrise <+rrise@users.noreply.github.com>
Reviewed-on: Siteworxpro/reloading-manager#7
Co-authored-by: Ron Rise <ron@siteworxpro.com>
Co-committed-by: Ron Rise <ron@siteworxpro.com>
2025-05-16 15:34:23 -04:00
c5f1f32b44 You know the rules and so do I
Some checks failed
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 10m30s
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 19m6s
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Successful in 20m46s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Failing after 1m18s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 22m13s
2025-05-16 14:05:49 -04:00
343abbb801 Actual final build before release
Some checks failed
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Failing after 2m42s
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Failing after 2m47s
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 18m37s
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Successful in 20m14s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Failing after 54s
2025-05-16 14:02:19 -04:00
13aad5254e Feed. You. Stuff. No time. (#6)
Some checks failed
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m16s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 3m53s
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 5m9s
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Successful in 6m9s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Failing after 9s
Reviewed-on: Siteworxpro/reloading-manager#6
Co-authored-by: Ron Rise <ron@siteworxpro.com>
Co-committed-by: Ron Rise <ron@siteworxpro.com>
2025-05-16 11:20:41 -04:00
aeba95dc41 [create-pull-request] automated change (#5)
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m15s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 3m14s
Co-authored-by: rrise <+rrise@users.noreply.github.com>
Reviewed-on: Siteworxpro/reloading-manager#5
Co-authored-by: Ron Rise <ron@siteworxpro.com>
Co-committed-by: Ron Rise <ron@siteworxpro.com>
2025-05-16 11:13:40 -04:00
b40edf70d4 and a comma (#4)
Some checks failed
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 2m50s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Failing after 2m45s
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m16s
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 5m25s
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Successful in 6m23s
Reviewed-on: Siteworxpro/reloading-manager#4
Co-authored-by: Ron Rise <ron@siteworxpro.com>
Co-committed-by: Ron Rise <ron@siteworxpro.com>
2025-05-16 10:21:03 -04:00
4f750ae15c [create-pull-request] automated change (#3)
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 8m6s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 10m49s
Co-authored-by: rrise <+rrise@users.noreply.github.com>
Reviewed-on: Siteworxpro/reloading-manager#3
Co-authored-by: Ron Rise <ron@siteworxpro.com>
Co-committed-by: Ron Rise <ron@siteworxpro.com>
2025-05-16 10:08:55 -04:00
3246450d77 Merge pull request 'This is not the commit message you are looking for' (#2) from deployments into master
Some checks failed
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 5m47s
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m15s
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Successful in 6m16s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Failing after 49s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 3m11s
Reviewed-on: Siteworxpro/reloading-manager#2
2025-05-16 09:47:00 -04:00
74681e01b3 This is not the commit message you are looking for
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m23s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 3m0s
2025-05-16 09:42:39 -04:00
9dce6b8930 various changes
Some checks failed
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 6m36s
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Successful in 7m45s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Failing after 52s
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 3m14s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 5m22s
2025-05-16 09:19:02 -04:00
7c02aa7148 Merge pull request '📝🔄 Update deployment manifest with new image tags' (#1) from release/v0.0.29-deploy into master
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 4m48s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 8m1s
Reviewed-on: Siteworxpro/reloading-manager#1
2025-05-16 09:09:05 -04:00
GitHub Action 🤖
a8c470a474 📝🔄 Update deployment manifest with new image tags 2025-05-16 13:01:57 +00:00
95b626b439 It's Working!
All checks were successful
🏗️ ✨ Build Workflow / 🖥️ 🔨 Build Backend (push) Successful in 7m3s
🏗️ ✨ Build Workflow / 🚀 ✨ Deploy Application (push) Successful in 57s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 5m7s
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 1m17s
🏗️ ✨ Build Workflow / 🖼️ 🔨 Build Frontend (push) Successful in 5m35s
2025-05-16 08:50:55 -04:00
b9a6598e87 Fucking templates.
All checks were successful
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Successful in 2m24s
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Successful in 5m18s
2025-05-16 08:45:01 -04:00
4251a03139 That last commit was cringe
Some checks failed
🧪 ✨ Unit Tests Workflow / 🔍 🐹 Go Tests (push) Has been cancelled
🧪 ✨ Unit Tests Workflow / 🧪 📜 JavaScript Tests (push) Has been cancelled
2025-05-16 08:44:02 -04:00
691a32ff56 Just committing so I can go home
All checks were successful
🧪✨ Unit Tests Workflow / 🔍🐹 Go Tests (push) Successful in 8m21s
🧪✨ Unit Tests Workflow / 🧪📜 JavaScript Tests (push) Successful in 1m8s
2025-05-16 08:29:57 -04:00
3631a4b5dc ci test 2025-04-21 18:39:16 -04:00
edbd5b4f49 I would rather be playing Destiny 2. 2025-04-21 18:35:37 -04:00
a20bef65ae should work now. 2025-04-21 18:34:38 -04:00
4056e6705d Merge branch 'update-deployment-v0.0.28' into 'master'
Update deployment manifest with new image tags

See merge request rrise/reloading-manager!2
2025-04-21 22:34:01 +00:00
fc4305f161 yo recipes 2025-04-21 18:32:09 -04:00
f0fc8b7707 Update deployment manifest with new image tags 2025-04-21 22:29:48 +00:00
32 changed files with 990 additions and 369 deletions

View File

@@ -1,7 +1,7 @@
on:
push:
tags:
- '**'
- 'v*'
name: 🏗️ ✨ Build Workflow
@@ -10,13 +10,6 @@ jobs:
name: 🖼️ 🔨 Build Frontend
runs-on: ubuntu-latest
steps:
- name: 🛡️🔒 Add Siteworx CA Certificates
run: |
apt update && apt install -yq ca-certificates curl
curl -Ls https://siteworxpro.com/hosted/Siteworx+Root+CA.pem -o /usr/local/share/ca-certificates/sw.crt
update-ca-certificates
- name: 📖 🔍 Checkout Repository Code
uses: actions/checkout@v2
with:
@@ -25,13 +18,13 @@ jobs:
- name: 🔑 🔐 Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: 🔑 🛠️ Login to Siteworx Registry
uses: docker/login-action@v3
with:
username: ${{ vars.SITEWORX_USERNAME }}
username: ${{ secrets.SITEWORX_USERNAME }}
password: ${{ secrets.SITEWORX_PASSWORD }}
registry: scr.siteworxpro.com
@@ -62,13 +55,6 @@ jobs:
name: 🖥️ 🔨 Build Backend
runs-on: ubuntu-latest
steps:
- name: 🛡️🔒 Add Siteworx CA Certificates
run: |
apt update && apt install -yq ca-certificates curl
curl -Ls https://siteworxpro.com/hosted/Siteworx+Root+CA.pem -o /usr/local/share/ca-certificates/sw.crt
update-ca-certificates
- name: 📖🔍 Checkout Repository Code
uses: actions/checkout@v2
with:
@@ -77,13 +63,13 @@ jobs:
- name: 🔑 🔐 Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: 🔑 🛠️ Login to Siteworx Registry
uses: docker/login-action@v3
with:
username: ${{ vars.SITEWORX_USERNAME }}
username: ${{ secrets.SITEWORX_USERNAME }}
password: ${{ secrets.SITEWORX_PASSWORD }}
registry: scr.siteworxpro.com
@@ -111,13 +97,6 @@ jobs:
runs-on: ubuntu-latest
needs: [BuildFrontend, BuildBackend]
steps:
- name: 🛡️🔒 Add Siteworx CA Certificates
run: |
apt update && apt install -yq ca-certificates curl
curl -Ls https://siteworxpro.com/hosted/Siteworx+Root+CA.pem -o /usr/local/share/ca-certificates/sw.crt
update-ca-certificates
- name: 📖 🔍 Checkout Repository Code
uses: actions/checkout@v2
with:
@@ -128,15 +107,36 @@ jobs:
echo "## Do not edit this file directly. It is auto-generated by the script." > argocd/deployment/deployment.yml
sed "s|__TAG__|${{ gitea.ref_name }}|g" argocd/template/deployment.yml >> argocd/deployment/deployment.yml
- name: 💾✅ Commit Updated Manifest
uses: EndBug/add-and-commit@v9
- name: 📤 📦 Recommit Build Artifacts
uses: addnab/docker-run-action@v3
with:
new_branch: release/${{ gitea.ref_name }}-deploy
add: argocd/deployment/deployment.yml
author_name: "GitHub Action 🤖"
author_email: gitia@siteworxpro.com
message: "📝🔄 Update deployment manifest with new image tags"
image: alpine/git
options: --volumes-from ${{ env.JOB_CONTAINER_NAME }} -w ${{ gitea.workspace }}
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keyscan -H gitea.siteworxpro.com >> ~/.ssh/known_hosts
echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa
git config --global user.email "gitea@siteworxpro.com"
git config --global user.name "Gitea-Runner via Gitea Actions"
git config --global push.autoSetupRemote true
git remote rm origin && git remote add origin "git@gitea.siteworxpro.com:siteworxpro/reloading-manager.git"
git add -f "argocd/deployment/*" || true
git checkout -b release/${{ gitea.ref_name }}-deploy || git checkout release/${{ gitea.ref_name }}-deploy
git commit -m "Build Auto Commit" || echo "No changes to commit"
git push origin release/${{ gitea.ref_name }} -o ci.skip || echo "No changes to push"
- name: 🚀 ✨ Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v7
env:
NODE_TLS_REJECT_UNAUTHORIZED: 0
with:
base: master
add-paths: argocd/deployment/deployment.yml
title: "🚀 ✨ Release ${GITHUB_REF_NAME} - Deploy"
branch: release/${{ gitea.ref_name }}-deploy
committer: "Gitea Action 🤖 <gitia@siteworxpro.com>"
body: "📝 🔄 Update deployment manifest with new image tags for release ${{ gitea.ref_name }}"

View File

@@ -1,5 +1,13 @@
on:
workflow_dispatch:
inputs:
test:
description: 'Run tests'
required: true
default: 'true'
push:
paths-ignore:
- argocd/**/*
branches:
- "*"
@@ -32,6 +40,29 @@ jobs:
cd frontend
npm run build
golangci-lint:
name: 🧪 🐹 GolangCI-Lint
runs-on: ubuntu-latest
steps:
- name: 🛡️ 🔒 Add Siteworx CA Certificates
run: |
apt update && apt install -yq ca-certificates curl
curl -Ls https://siteworxpro.com/hosted/Siteworx+Root+CA.pem -o /usr/local/share/ca-certificates/sw.crt
update-ca-certificates
- name: 📖 🔍 Checkout Repository Code
uses: actions/checkout@v2
with:
fetch-depth: 1
- name: ⚙️ 🐹 Set up Go Environment
uses: actions/setup-go@v2
with:
go-version: '1.25.6'
cache: true
- name: ✅ 🧪 Run GolangCI-Lint
uses: golangci/golangci-lint-action@v8.0.0
with:
working-directory: backend
test-go:
env:
GOPRIVATE: 'git.siteworxpro.com'
@@ -47,7 +78,7 @@ jobs:
- name: ⚙️ 🐹 Set up Go Environment
uses: actions/setup-go@v2
with:
go-version: '1.24.0'
go-version: '1.25.6'
cache: true
- name: 📖 🔍 Checkout Repository Code
uses: actions/checkout@v2

View File

@@ -9,8 +9,11 @@ stages:
NodeJs Tests:
stage: Tests
image: node:22.14.0
except:
- tags
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
changes:
- frontend/**
- frontend/.gitlab-ci.yml
before_script:
- cd frontend
- npm install
@@ -21,6 +24,11 @@ include:
- project: 'shared/blueprints'
file: 'jobs/golang-tests.yml'
ref: master
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
changes:
- backend/**
- backend/.gitlab-ci.yml
inputs:
job_name: "Go Tests"
working_directory: "backend"
@@ -62,6 +70,18 @@ include:
context: "frontend"
dockerfile: "frontend/Dockerfile"
- project: 'shared/blueprints'
file: 'jobs/trigger-argocd.yml'
ref: master
rules:
- changes:
- argocd/**/*
inputs:
stage: Trigger
argocdServer: ${ARGOCD_SERVER}
argocdAuthToken: ${ARGOCD_AUTH_TOKEN}
argocdAppName: ${ARGOCD_APP_NAME}
Update Deployment:
image: siteworxpro/alpine:3.21.3
rules:
@@ -108,19 +128,8 @@ Create Merge Request:
curl --request POST --header "PRIVATE-TOKEN: glpat-hv-uxCx3PDNKn7ihyXce" \
--data "source_branch=update-deployment-${CI_COMMIT_TAG}" \
--data "target_branch=master" \
--data "title=Update deployment manifest with new image tags" \
--data "title=Update deployment manifest for version ${CI_COMMIT_TAG}" \
--data "description=This merge request updates the deployment manifest with the new image tags." \
--data "remove_source_branch=true" \
--data "squash_commits=true" \
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests"
Trigger ArgoCD:
stage: Trigger
image: siteworxpro/argocd:v2.14.10
rules:
- changes:
- argocd/deployment/*
variables:
ARGOCD_AUTH_TOKEN: ${ARGOCD_AUTH_TOKEN}
ARGOCD_SERVER: ${ARGOCD_SERVER}
script: |
argocd --grpc-web app sync ${ARGOCD_APP_NAME}

View File

@@ -3,7 +3,7 @@ kind: ConfigMap
metadata:
name: reloading-cm
data:
DB_HOST: "192.168.1.30"
DB_HOST: "postgres.postgres.svc.cluster.local"
DB_DATABASE: "loading"
DB_USER: "loading"
DB_PASSWORD: "loading"

View File

@@ -19,11 +19,11 @@ spec:
- name: siteworxpro
containers:
- name: frontend
image: scr.siteworxpro.com/reloading-manager/frontend:v0.0.27
image: scr.siteworxpro.com/reloading-manager/frontend:v0.0.37
ports:
- containerPort: 80
- name: backend
image: scr.siteworxpro.com/reloading-manager/backend:v0.0.27
image: scr.siteworxpro.com/reloading-manager/backend:v0.0.37
ports:
- containerPort: 8080
envFrom:

17
backend/.golangci.yml Normal file
View File

@@ -0,0 +1,17 @@
version: "2"
linters:
default: standard
enable:
- whitespace
- tagalign
- reassign
- bodyclose
- contextcheck
- containedctx
- godot
- usestdlibvars
formatters:
settings:
gofmt:
simplify: true

View File

@@ -1,4 +1,4 @@
FROM siteworxpro/golang:1.24.0 AS build
FROM siteworxpro/golang:1.25.6 AS build
WORKDIR /app

View File

@@ -4,7 +4,7 @@ docker run -v $(pwd)/postgres:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=password \
--rm --name postgres \
-p 5432:5432 \
-d scr.siteworxpro.com/library/postgres:17
-d postgres:17
```
```shell

View File

@@ -3,12 +3,12 @@ package database
import (
"context"
"fmt"
"git.siteworxpro.com/packages/go/utilities/Env"
"git.siteworxpro.com/reloading-manager/backend/models/bullets"
"git.siteworxpro.com/reloading-manager/backend/models/loads"
"git.siteworxpro.com/reloading-manager/backend/models/manufacturer"
"git.siteworxpro.com/reloading-manager/backend/models/powder"
"git.siteworxpro.com/reloading-manager/backend/models/primers"
"gitea.siteworxpro.com/golang-packages/utilities/Env"
"github.com/jackc/pgx/v5"
"log"
)
@@ -20,6 +20,10 @@ const (
DbPassword Env.EnvironmentVariable = "DB_PASSWORD"
)
type contextKeyType string
const dbContextKey contextKeyType = "dbcontext"
type Database struct {
Db *pgx.Conn
connected bool
@@ -50,6 +54,24 @@ func (*Database) DSN(hidePassword bool) string {
return fmt.Sprintf("postgres://%s:%s@%s:5432/%s%s", dbUser, dbPassword, dbHost, dbDatabase, extraParams)
}
func NewWithContext(ctx context.Context) context.Context {
db := GetNewDatabase()
return context.WithValue(ctx, dbContextKey, db)
}
func NewFromContext(ctx context.Context) *Database {
if ok := ctx.Value(dbContextKey); ok != nil {
return ctx.Value(dbContextKey).(*Database)
}
return nil
}
func WithContext(ctx context.Context, database *Database) context.Context {
return context.WithValue(ctx, dbContextKey, database)
}
func GetNewDatabase() *Database {
var dbSingleton Database

View File

@@ -11,6 +11,9 @@ import (
func (db *Database) Migrate() {
sqlDB, err := sql.Open("postgres", db.DSN(false))
if err != nil {
log.Fatal(err)
}
driver, err := postgres.WithInstance(sqlDB, &postgres.Config{
MigrationsTable: "schema_migrations",

View File

@@ -1,16 +1,16 @@
module git.siteworxpro.com/reloading-manager/backend
go 1.24.0
go 1.25.6
require (
git.siteworxpro.com/packages/go/utilities v1.3.0
gitea.siteworxpro.com/golang-packages/utilities v1.0.0
github.com/go-jet/jet/v2 v2.13.0
github.com/go-playground/validator v9.31.0+incompatible
github.com/go-sql-driver/mysql v1.9.2
github.com/golang-migrate/migrate v3.5.4+incompatible
github.com/google/uuid v1.6.0
github.com/jackc/pgx/v5 v5.7.4
github.com/labstack/echo/v4 v4.13.3
github.com/jackc/pgx/v5 v5.7.5
github.com/labstack/echo/v4 v4.13.4
github.com/labstack/gommon v0.4.2
)
@@ -41,11 +41,11 @@ require (
github.com/stretchr/testify v1.10.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/time v0.12.0 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -1,7 +1,7 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.siteworxpro.com/packages/go/utilities v1.3.0 h1:931q66COBJATgIQksPDSZlWMIwENJhhfC/GVf22ER5s=
git.siteworxpro.com/packages/go/utilities v1.3.0/go.mod h1:iWhICNrMnB03PY9dM9eCNs9uQPEsPwae5pJDG+HHUPI=
gitea.siteworxpro.com/golang-packages/utilities v1.0.0 h1:f5JqAeZWBn/HBO9k5dzg0Wm91a69uwU5UC2P9ebQ9J0=
gitea.siteworxpro.com/golang-packages/utilities v1.0.0/go.mod h1:QNqclnfv/BT2D5tbXgsGm7uhhe2Baovi5F6j0pVvMGc=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -40,8 +40,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@@ -50,8 +50,8 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
@@ -86,41 +86,41 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -21,12 +21,15 @@ type BulletResponse struct {
func Photo(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
id := c.Param("id")
uid := handlers.ParseUuidOrBadRequest(c, id)
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID format")
}
byId, err := db.Bullets.GetBulletById(context.Background(), *uid)
@@ -48,15 +51,18 @@ func Photo(c echo.Context) error {
func Delete(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
id := c.Param("id")
uid := handlers.ParseUuidOrBadRequest(c, id)
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, id)
if err != nil || uid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID format")
}
err := db.Bullets.DeleteBullet(context.Background(), *uid)
err = db.Bullets.DeleteBullet(context.Background(), *uid)
if err != nil {
return err
}
@@ -66,12 +72,14 @@ func Delete(c echo.Context) error {
func Put(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
id := c.Param("id")
uid := handlers.ParseUuidOrBadRequest(c, id)
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, id)
if err != nil || uid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID format")
}
byId, err := db.Bullets.GetBulletById(context.Background(), *uid)
@@ -101,9 +109,9 @@ func Put(c echo.Context) error {
weight, _ := strconv.ParseInt(c.FormValue("weight"), 10, 32)
diameter, _ := strconv.ParseInt(c.FormValue("diameter"), 10, 32)
manufacturerId := c.FormValue("manufacturer_id")
manufacturerUid := handlers.ParseUuidOrBadRequest(c, manufacturerId)
if manufacturerUid == nil {
return nil
manufacturerUid, err := handlers.ParseUuidOrBadRequest(c, manufacturerId)
if err == nil || manufacturerUid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID format")
}
name := c.FormValue("name")
@@ -147,13 +155,15 @@ func Put(c echo.Context) error {
func Get(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
if c.Param("id") != "" {
id := c.Param("id")
uid := handlers.ParseUuidOrBadRequest(c, id)
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, id)
if err != nil || uid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID format")
}
byId, err := db.Bullets.GetBulletById(context.Background(), *uid)
@@ -210,7 +220,6 @@ func Get(c echo.Context) error {
}
func Post(c echo.Context) error {
file, err := c.FormFile("photo")
if err != nil {
c.Logger().Error(err)
@@ -245,11 +254,13 @@ func Post(c echo.Context) error {
}
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
manufacturerUid := handlers.ParseUuidOrBadRequest(c, manufacturerId)
if manufacturerUid == nil {
return nil
manufacturerUid, err := handlers.ParseUuidOrBadRequest(c, manufacturerId)
if err != nil || manufacturerUid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID format")
}
manufacturer, err := db.Manufacturer.GetById(context.Background(), *manufacturerUid)

View File

@@ -22,7 +22,9 @@ type postRequest struct {
func Get(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
cartridges, err := db.Loads.GetCartridges(context.Background())
if err != nil {
@@ -45,7 +47,9 @@ func Get(c echo.Context) error {
func Post(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
req := postRequest{}
@@ -79,14 +83,16 @@ func Post(c echo.Context) error {
func Delete(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
uid := handlers.ParseUuidOrBadRequest(c, c.Param("id"))
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, c.Param("id"))
if err != nil || uid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "invalid id")
}
err := db.Loads.DeleteCartridge(context.Background(), *uid)
err = db.Loads.DeleteCartridge(context.Background(), *uid)
if err != nil {
return err

View File

@@ -2,18 +2,12 @@ package handlers
import (
"github.com/labstack/echo/v4"
"net/http"
)
func ReadFile(c echo.Context, formName string) ([]byte, error) {
file, err := c.FormFile(formName)
if err != nil {
c.Logger().Error(err)
_ = c.JSON(http.StatusBadRequest, struct {
Message string `json:"message"`
}{
Message: "No file provided",
})
return nil, err
}

View File

@@ -2,7 +2,6 @@ package loads
import (
"context"
"fmt"
"git.siteworxpro.com/reloading-manager/backend/.gen/loading/public/table"
"git.siteworxpro.com/reloading-manager/backend/database"
"git.siteworxpro.com/reloading-manager/backend/handlers"
@@ -10,8 +9,10 @@ import (
"git.siteworxpro.com/reloading-manager/backend/handlers/primers"
"git.siteworxpro.com/reloading-manager/backend/models/loads"
"github.com/go-jet/jet/v2/postgres"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4"
"mime"
"net/http"
"strings"
)
@@ -45,6 +46,7 @@ type row struct {
type loadResponseResults struct {
Id string `json:"id"`
Cartridge string `json:"cartridge"`
CartridgeId string `json:"cartridge_id"`
Col float32 `json:"col"`
Powder handlers.Powder `json:"powder"`
PowderGr float32 `json:"powder_gr"`
@@ -63,8 +65,28 @@ type ResultChan[T any] struct {
}
func Post(c echo.Context) error {
var exists *loads.GetLoadByIdRow
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
id := c.Param("id")
if id != "" {
uuid, err := handlers.ParseUuid(id)
if err != nil {
return handlers.BadRequest(c, "id is not a valid UUID")
}
gbi, err := db.Loads.GetLoadById(context.Background(), *uuid)
if err != nil || !gbi.ID.Valid {
return handlers.NotFound(c, "load not found")
}
exists = &gbi
}
cartridgeID, err := handlers.ParseUuid(c.FormValue("cartridge_id"))
if err != nil {
@@ -87,8 +109,11 @@ func Post(c echo.Context) error {
}
file, err := handlers.ReadFile(c, "photo")
if err != nil {
if err != nil && exists == nil {
return handlers.BadRequest(c, "photo is not valid")
} else if err != nil {
// If we are updating an existing load, we can ignore the error
file = exists.Photo
}
meta := c.FormValue("meta")
@@ -115,6 +140,26 @@ func Post(c echo.Context) error {
return handlers.BadRequest(c, "col is not valid")
}
if exists != nil {
err = db.Loads.UpdateLoad(context.Background(), loads.UpdateLoadParams{
ID: exists.ID,
CartridgeID: *cartridgeID,
Col: colFl,
PowderID: *powderId,
PowderGr: powderGrFl,
PrimerID: *primerId,
BulletID: *bulletId,
Photo: file,
Meta: []byte(meta),
})
if err != nil {
return err
}
return c.JSON(http.StatusOK, handlers.Response[string]{Payload: exists.ID.String()})
}
uid, err := db.Loads.CreateLoad(context.Background(), loads.CreateLoadParams{
CartridgeID: *cartridgeID,
Col: colFl,
@@ -133,16 +178,66 @@ func Post(c echo.Context) error {
return c.JSON(http.StatusCreated, handlers.Response[string]{Payload: uid.String()})
}
func Photo(c echo.Context) error {
id := c.Param("id")
if id == "" {
return handlers.BadRequest(c, "id is required")
}
uuid, err := handlers.ParseUuid(id)
if err != nil {
return handlers.BadRequest(c, "id is not a valid UUID")
}
db := c.(*database.CustomContext).Db
defer func() {
_ = db.Db.Close(context.Background())
}()
file, err := db.Loads.GetLoadById(context.Background(), *uuid)
if err != nil {
return handlers.NotFound(c, "load photo not found")
}
mt, _, _ := mime.ParseMediaType(string(file.Photo))
return c.Blob(http.StatusOK, mt, file.Photo)
}
func Get(c echo.Context) error {
cTotal := make(chan ResultChan[int64])
id := c.Param("id")
cResults := make(chan ResultChan[[]loadResponseResults])
if id != "" {
go execResultsQuery(cResults, c)
results := <-cResults
if results.Err != nil {
return results.Err
}
if len(results.Result) == 0 {
return handlers.NotFound(c, "load not found")
}
return c.JSON(http.StatusOK, handlers.Response[loadResponseResults]{Status: http.StatusText(http.StatusOK), Payload: results.Result[0]})
}
cTotal := make(chan ResultChan[int64])
go func(ch chan ResultChan[int64]) {
db := database.GetNewDatabase()
defer db.Db.Close(context.Background())
defer func(Db *pgx.Conn, ctx context.Context) {
_ = Db.Close(ctx)
}(db.Db, context.Background())
q := getQuery(c, true)
if q == nil {
ch <- ResultChan[int64]{Result: 0}
return
}
sql, params := q.Sql()
var total int64
@@ -155,24 +250,41 @@ func Get(c echo.Context) error {
} else {
ch <- ResultChan[int64]{Result: total}
}
}(cTotal)
go execResultsQuery(cResults, c)
go func(ch chan ResultChan[[]loadResponseResults]) {
total := <-cTotal
if total.Err != nil {
return total.Err
}
results := <-cResults
if results.Err != nil {
return results.Err
}
return c.JSON(http.StatusOK, handlers.Response[loadResponse]{Status: http.StatusText(http.StatusOK), Payload: loadResponse{Total: int(total.Result), Results: results.Result}})
}
func execResultsQuery(ch chan ResultChan[[]loadResponseResults], c echo.Context) {
db := database.GetNewDatabase()
defer db.Db.Close(context.Background())
defer func(Db *pgx.Conn, ctx context.Context) {
_ = Db.Close(ctx)
}(db.Db, context.Background())
q := getQuery(c, false)
fmt.Println(q.DebugSql())
if q == nil {
ch <- ResultChan[[]loadResponseResults]{Result: []loadResponseResults{}}
return
}
sql, params := q.Sql()
rows, err := db.Db.Query(context.Background(), sql, params...)
if err != nil {
ch <- ResultChan[[]loadResponseResults]{Err: err}
return
}
@@ -218,6 +330,7 @@ func Get(c echo.Context) error {
results = append(results, loadResponseResults{
Id: row.ID.String(),
Cartridge: row.CartridgeName,
CartridgeId: row.CartridgeID.String(),
Col: row.Col,
Powder: handlers.Powder{
Id: row.PowderID.String(),
@@ -251,19 +364,6 @@ func Get(c echo.Context) error {
}
ch <- ResultChan[[]loadResponseResults]{Result: results}
}(cResults)
total := <-cTotal
if total.Err != nil {
return total.Err
}
results := <-cResults
if results.Err != nil {
return results.Err
}
return c.JSON(http.StatusOK, handlers.Response[loadResponse]{Status: http.StatusText(http.StatusOK), Payload: loadResponse{Total: int(total.Result), Results: results.Result}})
}
func getQuery(c echo.Context, countOnly bool) postgres.SelectStatement {
@@ -289,7 +389,6 @@ func getQuery(c echo.Context, countOnly bool) postgres.SelectStatement {
if countOnly {
q = tb.SELECT(postgres.COUNT(l.ID).AS("total"))
} else {
q = tb.SELECT(
// Load
l.ID.AS("id"),
@@ -329,6 +428,17 @@ func getQuery(c echo.Context, countOnly bool) postgres.SelectStatement {
// where expressions
expressions := make([]postgres.BoolExpression, 0)
if c.Param("id") != "" {
uuid, err := handlers.ParseUuid(c.Param("id"))
if err != nil {
return nil
}
q = q.WHERE(l.ID.EQ(postgres.UUID(uuid)))
return q
}
if c.QueryParam("cartridge_id") != "" {
ids := strings.Split(c.QueryParam("cartridge_id"), ",")
if len(ids) > 0 {
@@ -438,17 +548,48 @@ func getQuery(c echo.Context, countOnly bool) postgres.SelectStatement {
if limit == "" {
limit = "50"
}
offset := c.QueryParam("offset")
if offset == "" {
offset = "0"
pageInt := handlers.ParseInt64OrDefault(c.QueryParam("page"), 1)
if pageInt < 1 {
pageInt = 1
}
offset := (pageInt - 1) * handlers.ParseInt64OrDefault(limit, 50)
q = q.LIMIT(handlers.ParseInt64OrDefault(limit, 50)).
OFFSET(handlers.ParseInt64OrDefault(offset, 0))
OFFSET(offset)
return q
}
func Delete(c echo.Context) error {
id := c.Param("id")
if id == "" {
return handlers.BadRequest(c, "id is required")
}
uuid, err := handlers.ParseUuid(id)
if err != nil {
return handlers.BadRequest(c, "id is not a valid UUID")
}
db := c.(*database.CustomContext).Db
defer func() {
_ = db.Db.Close(context.Background())
}()
exists, err := db.Loads.GetLoadById(context.Background(), *uuid)
if err != nil || !exists.ID.Valid {
return handlers.NotFound(c, "load not found")
}
err = db.Loads.DeleteLoad(context.Background(), *uuid)
if err != nil {
return err
}
return c.NoContent(http.StatusNoContent)
}
func getUuidExpr(ids []string) []postgres.Expression {
expr := make([]postgres.Expression, 0)
for _, id := range ids {

View File

@@ -21,13 +21,15 @@ type manufacturerResponse struct {
func Get(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
if c.Param("id") != "" {
id := c.Param("id")
uid := handlers.ParseUuidOrBadRequest(c, id)
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, id)
if err != nil || uid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID format")
}
byId, err := db.Manufacturer.GetById(context.Background(), *uid)
@@ -73,15 +75,17 @@ func Get(c echo.Context) error {
func Delete(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
id := c.Param("id")
uid := handlers.ParseUuidOrBadRequest(c, id)
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, id)
if err != nil || uid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID format")
}
_, err := db.Manufacturer.GetById(context.Background(), *uid)
_, err = db.Manufacturer.GetById(context.Background(), *uid)
if err != nil {
return echo.NewHTTPError(http.StatusNotFound, "Not found")
}
@@ -97,16 +101,18 @@ func Delete(c echo.Context) error {
func Post(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
if c.Param("id") != "" {
id := c.Param("id")
uid := handlers.ParseUuidOrBadRequest(c, id)
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, id)
if err != nil || uid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID format")
}
_, err := db.Manufacturer.GetById(context.Background(), *uid)
_, err = db.Manufacturer.GetById(context.Background(), *uid)
if err != nil {
return echo.NewHTTPError(http.StatusNotFound, "Not found")
}

View File

@@ -13,7 +13,9 @@ import (
func Photo(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
id := c.Param("id")
uid, err := handlers.ParseUuid(id)
@@ -41,7 +43,9 @@ func Photo(c echo.Context) error {
func Delete(c echo.Context) error {
id := c.Param("id")
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
uid, err := handlers.ParseUuid(id)
if err != nil {
@@ -58,7 +62,9 @@ func Delete(c echo.Context) error {
func Post(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
if c.Param("id") != "" {
id := c.Param("id")
@@ -163,7 +169,9 @@ func Post(c echo.Context) error {
func Get(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
if c.Param("id") != "" {
id := c.Param("id")

View File

@@ -3,6 +3,7 @@ package primers
import (
"context"
"encoding/json"
"fmt"
"git.siteworxpro.com/reloading-manager/backend/database"
"git.siteworxpro.com/reloading-manager/backend/handlers"
"git.siteworxpro.com/reloading-manager/backend/models/primers"
@@ -19,7 +20,9 @@ type PrimerResponse struct {
func Delete(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
id := c.Param("id")
uid, err := handlers.ParseUuid(id)
@@ -37,13 +40,15 @@ func Delete(c echo.Context) error {
func Post(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
if c.Param("id") != "" {
id := c.Param("id")
uid := handlers.ParseUuidOrBadRequest(c, id)
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, id)
if err != nil || uid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID.")
}
p, err := db.Primer.GetPrimerById(context.Background(), *uid)
@@ -56,9 +61,9 @@ func Post(c echo.Context) error {
}
if c.FormValue("manufacturer_id") != "" {
mid := handlers.ParseUuidOrBadRequest(c, c.FormValue("manufacturer_id"))
if mid == nil {
return nil
mid, err := handlers.ParseUuidOrBadRequest(c, c.FormValue("manufacturer_id"))
if err != nil || mid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid Manufacturer ID.")
}
p.ManufacturerID = *mid
@@ -112,13 +117,14 @@ func Post(c echo.Context) error {
if metaString == "" {
metaString = "{}"
}
var meta json.RawMessage = []byte(metaString)
meta := []byte(metaString)
newUuid := uuid.New().String()
uid, _ := handlers.ParseUuid(newUuid)
mid := handlers.ParseUuidOrBadRequest(c, manufacturerId)
if mid == nil {
return nil
mid, err := handlers.ParseUuidOrBadRequest(c, manufacturerId)
if err != nil || mid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid Manufacturer ID.")
}
err = db.Primer.InsertPrimer(context.Background(), primers.InsertPrimerParams{
@@ -145,12 +151,14 @@ func Post(c echo.Context) error {
func Photo(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
id := c.Param("id")
uid := handlers.ParseUuidOrBadRequest(c, id)
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, id)
if err != nil || uid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID.")
}
byId, err := db.Primer.GetPrimerById(context.Background(), *uid)
@@ -172,18 +180,20 @@ func Photo(c echo.Context) error {
func Get(c echo.Context) error {
db := c.(*database.CustomContext).Db
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
if c.Param("id") != "" {
id := c.Param("id")
uid := handlers.ParseUuidOrBadRequest(c, id)
if uid == nil {
return nil
uid, err := handlers.ParseUuidOrBadRequest(c, id)
if err != nil || uid == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID.")
}
row, err := db.Primer.GetPrimerById(context.Background(), *uid)
if err != nil {
return err
return fmt.Errorf("primer not found: %v", err)
}
return c.JSON(http.StatusOK, handlers.Response[PrimerResponse]{

View File

@@ -11,7 +11,6 @@ type TestContext struct {
}
func (t TestContext) JSON(code int, i interface{}) error {
if code != 400 {
t.t.Fatal("expected 400")
}

View File

@@ -1,6 +1,7 @@
package handlers
import (
"fmt"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4"
@@ -23,7 +24,7 @@ func ParseUuidOrEmpty(s string) *pgtype.UUID {
func ParseUuid(s string) (*pgtype.UUID, error) {
uid, err := uuid.Parse(s)
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid UUID format: %v", err)
}
return &pgtype.UUID{
@@ -32,14 +33,11 @@ func ParseUuid(s string) (*pgtype.UUID, error) {
}, nil
}
func ParseUuidOrBadRequest(c echo.Context, s string) *pgtype.UUID {
func ParseUuidOrBadRequest(c echo.Context, s string) (*pgtype.UUID, error) {
uid, err := ParseUuid(s)
if err != nil {
_ = BadRequest(c, "Invalid UUID.")
return nil
return nil, BadRequest(c, fmt.Sprintf("invalid UUID. %v", err))
}
return uid
return uid, nil
}

View File

@@ -3,7 +3,6 @@ package main
import (
"context"
"fmt"
"git.siteworxpro.com/packages/go/utilities/Env"
"git.siteworxpro.com/reloading-manager/backend/database"
"git.siteworxpro.com/reloading-manager/backend/handlers/bullets"
"git.siteworxpro.com/reloading-manager/backend/handlers/cartridge"
@@ -11,6 +10,7 @@ import (
"git.siteworxpro.com/reloading-manager/backend/handlers/manufacturer"
"git.siteworxpro.com/reloading-manager/backend/handlers/powder"
"git.siteworxpro.com/reloading-manager/backend/handlers/primers"
"gitea.siteworxpro.com/golang-packages/utilities/Env"
"github.com/go-playground/validator"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
@@ -98,7 +98,11 @@ func main() {
// loads
e.GET("/load", loads.Get)
e.GET("/load/:id", loads.Get)
e.GET("/load/:id/photo", loads.Photo)
e.POST("/load", loads.Post)
e.POST("/load/:id", loads.Post)
e.DELETE("/load/:id", loads.Delete)
addr := fmt.Sprintf("0.0.0.0:%s", Port.GetEnvString("8080"))
@@ -113,7 +117,9 @@ func migrate(e *echo.Echo) {
db := database.GetNewDatabase()
defer db.Db.Close(context.Background())
defer func() {
_ = db.Db.Close(context.Background())
}()
db.Migrate()
e.Logger.Info("✅ Complete!")

View File

@@ -18,6 +18,22 @@ delete
from cartridges
where id = $1;
-- name: DeleteLoad :exec
delete from loads
where id = $1;
-- name: UpdateLoad :exec
update loads set
cartridge_id = $1,
col = $2,
powder_id = $3,
powder_gr = $4,
primer_id = $5,
bullet_id = $6,
photo = $7,
meta = $8
where id = $9;
-- name: CreateLoad :one
insert into loads (cartridge_id, col, powder_id, powder_gr, primer_id, bullet_id, photo, meta)
values ($1, $2, $3, $4, $5, $6, $7, $8)
@@ -25,6 +41,7 @@ returning id;
-- name: GetLoadById :one
select l.id as id,
l.photo as photo,
c.id as cartridge_id,
c.name as cartridge_name,
c.meta as cartridge_meta,

View File

@@ -73,6 +73,16 @@ func (q *Queries) DeleteCartridge(ctx context.Context, id pgtype.UUID) error {
return err
}
const deleteLoad = `-- name: DeleteLoad :exec
delete from loads
where id = $1
`
func (q *Queries) DeleteLoad(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, deleteLoad, id)
return err
}
const getCartridgeById = `-- name: GetCartridgeById :one
select c.id as id, c.name, c.meta
from cartridges c
@@ -126,6 +136,7 @@ func (q *Queries) GetCartridges(ctx context.Context) ([]GetCartridgesRow, error)
const getLoadById = `-- name: GetLoadById :one
select l.id as id,
l.photo as photo,
c.id as cartridge_id,
c.name as cartridge_name,
c.meta as cartridge_meta,
@@ -147,6 +158,7 @@ where l.id = $1
type GetLoadByIdRow struct {
ID pgtype.UUID `json:"id"`
Photo []byte `json:"photo"`
CartridgeID pgtype.UUID `json:"cartridge_id"`
CartridgeName string `json:"cartridge_name"`
CartridgeMeta []byte `json:"cartridge_meta"`
@@ -165,6 +177,7 @@ func (q *Queries) GetLoadById(ctx context.Context, id pgtype.UUID) (GetLoadByIdR
var i GetLoadByIdRow
err := row.Scan(
&i.ID,
&i.Photo,
&i.CartridgeID,
&i.CartridgeName,
&i.CartridgeMeta,
@@ -376,3 +389,43 @@ func (q *Queries) TotalLoads(ctx context.Context) (int64, error) {
err := row.Scan(&count)
return count, err
}
const updateLoad = `-- name: UpdateLoad :exec
update loads set
cartridge_id = $1,
col = $2,
powder_id = $3,
powder_gr = $4,
primer_id = $5,
bullet_id = $6,
photo = $7,
meta = $8
where id = $9
`
type UpdateLoadParams struct {
CartridgeID pgtype.UUID `json:"cartridge_id"`
Col float32 `json:"col"`
PowderID pgtype.UUID `json:"powder_id"`
PowderGr float32 `json:"powder_gr"`
PrimerID pgtype.UUID `json:"primer_id"`
BulletID pgtype.UUID `json:"bullet_id"`
Photo []byte `json:"photo"`
Meta []byte `json:"meta"`
ID pgtype.UUID `json:"id"`
}
func (q *Queries) UpdateLoad(ctx context.Context, arg UpdateLoadParams) error {
_, err := q.db.Exec(ctx, updateLoad,
arg.CartridgeID,
arg.Col,
arg.PowderID,
arg.PowderGr,
arg.PrimerID,
arg.BulletID,
arg.Photo,
arg.Meta,
arg.ID,
)
return err
}

View File

@@ -1 +1 @@
v22.14.0
v25.4.0

View File

@@ -1685,13 +1685,13 @@
}
},
"node_modules/axios": {
"version": "1.8.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz",
"integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
@@ -1703,9 +1703,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2031,14 +2031,15 @@
}
},
"node_modules/form-data": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
@@ -2758,6 +2759,51 @@
"node": ">=6"
}
},
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.3"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/tinyglobby/node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -2817,14 +2863,17 @@
}
},
"node_modules/vite": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz",
"integrity": "sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==",
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"license": "MIT",
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
"picomatch": "^4.0.2",
"postcss": "^8.5.3",
"rollup": "^4.30.1"
"rollup": "^4.34.9",
"tinyglobby": "^0.2.13"
},
"bin": {
"vite": "bin/vite.js"
@@ -2887,6 +2936,35 @@
}
}
},
"node_modules/vite/node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/vite/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/vscode-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",

View File

@@ -0,0 +1,49 @@
<template>
<div class="loader" v-if="loading">
<div class="flex flex-col justify-center items-center">
<ProgressSpinner :style="{ width: '50px', height: '50px' }" strokeWidth="5" />
</div>
<div class="flex flex-row justify-center items-center">
<span class="text-2xl">{{ message }}</span>
</div>
</div>
</template>
<script setup lang="ts">
import { defineAsyncComponent } from 'vue'
const ProgressSpinner = defineAsyncComponent(() => import('primevue/progressspinner'))
defineProps({
loading: {
type: Boolean,
default: false
},
message: {
type: String,
default: 'Loading...'
}
})
</script>
<style scoped lang="scss">
.loader {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(9, 5, 5, 0.56);
z-index: 1000;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.text-2xl {
margin-top: 10px;
font-size: 24px;
font-weight: bold;
color: #ffffff;
}
}
</style>

View File

@@ -5,4 +5,5 @@ export const icons = {
upload: 'fa-thin fa-sharp fa-upload',
save: 'fa-thin fa-sharp fa-floppy-disk',
delete: 'fa-thin fa-sharp fa-trash',
loading: 'fa-solid fa-sharp fa-cog fa-spin',
}

View File

@@ -1,7 +1,8 @@
<template>
<Card class="md:w-2/3 w-full">
<template #title>
Add New Load
<span v-if="route.params.id">Edit Load</span>
<span v-else>Add New Load</span>
</template>
<template #content>
<div class="grid grid-cols-1">
@@ -66,7 +67,7 @@
COL
</div>
<div class="w-full mt-3">
<InputMask placeholder="0.000" v-model="load.col" mask="9.999" class="w-full" />
<InputMask :unmask="loading" :value="load.col" placeholder="0.000" v-model="load.col" mask="9.999" class="w-full" />
<Message v-if="v$.$dirty && v$.col.$invalid" :value="false" size="small" severity="error"
variant="simple">COL Required
</Message>
@@ -74,15 +75,20 @@
<div class="w-full mt-5">
<label>Picture</label>
<Message v-if="v$.$dirty && !file" :value="false" size="small" severity="error"
<Message v-if="v$.$dirty && (!route.params.id && !file)" :value="false" size="small" severity="error"
variant="simple">Picture Required
</Message>
<div class="w-1/2">
<img v-if="pictureUrl && route.params.id && !loading" :src="pictureUrl" alt="picture" />
</div>
<FileUpload v-model="file" mode="basic" @select="fileSelected" customUpload />
</div>
</div>
</template>
<template #footer>
<Button label="Add" :icon="icons.add" @click="add" />
<Button v-if="!route.params.id" label="Add" :icon="icons.add" @click="add" />
<Button v-else label="Save" :icon="icons.edit" @click="add" />
<Button class="ml-3" severity="danger" v-if="route.params.id" label="Delete" :icon="icons.delete" @click="deleteLoad" />
</template>
</Card>
@@ -103,6 +109,7 @@
</template>
</Dialog>
<FullScreenLoader :loading="loading" />
</template>
<script lang="ts">
interface Select {
@@ -121,13 +128,16 @@ import { defineAsyncComponent, onMounted, ref } from 'vue'
import { Primers } from '../../types/primers'
import { Powder } from '../../types/powder'
import axios from 'axios'
import { Response } from '../../types/Response'
import { Load, Response } from '../../types/Response'
import { icons } from '../../lib/icons.ts'
import { FileUploadSelectEvent } from 'primevue/fileupload'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import { useToast } from 'primevue/usetoast'
import router from '../../router'
import { useRoute, useRouter } from 'vue-router'
const router = useRouter()
const route = useRoute()
const Card = defineAsyncComponent(() => import('primevue/card'))
const Select = defineAsyncComponent(() => import('primevue/select'))
@@ -138,6 +148,7 @@ const InputMask = defineAsyncComponent(() => import('primevue/inputmask'))
const FileUpload = defineAsyncComponent(() => import('primevue/fileupload'))
const Dialog = defineAsyncComponent(() => import('primevue/dialog'))
const Message = defineAsyncComponent(() => import('primevue/message'))
const FullScreenLoader = defineAsyncComponent(() => import('../../components/FullScreenLoader.vue'))
const toast = useToast()
@@ -145,6 +156,7 @@ const bullets = ref<Select[]>([])
const primers = ref<Select[]>([])
const powders = ref<Select[]>([])
const cartridges = ref<Select[]>([])
const loading = ref(false)
const cartridgeName = ref('')
const addCartridgeDialog = ref(false)
@@ -154,6 +166,12 @@ const fileSelected = (e: FileUploadSelectEvent) => {
file.value = e.files[0]
}
const pictureUrl = ref<string | null>(null)
const calcUrl = () => {
const cache = new Date().getMilliseconds()
pictureUrl.value = import.meta.env.VITE_API + `/load/${route.params.id}/photo?cache=${cache}`
}
const load = ref({
bullet: '',
cartridge: '',
@@ -191,21 +209,18 @@ const fetchBullets = async () => {
bullets.value.push({ label: `${bullet.manufacturer.name} ${bullet.weight}gr ${bullet.name}`, value: bullet.id })
})
}
const fetchPrimers = async () => {
const response = await axios.get<any, Response<Primers[]>>(`${import.meta.env.VITE_API}/primer`)
response.data.payload.forEach((primer: Primers) => {
primers.value.push({ label: `${primer.manufacturer.name} ${primer.name}`, value: primer.id })
})
}
const fetchPowders = async () => {
const response = await axios.get<any, Response<Powder[]>>(`${import.meta.env.VITE_API}/powder`)
response.data.payload.forEach((powder: Powder) => {
powders.value.push({ label: `${powder.manufacturer.name} ${powder.name}`, value: powder.id })
})
}
const fetchCartridges = async () => {
cartridges.value = []
@@ -214,7 +229,6 @@ const fetchCartridges = async () => {
cartridges.value.push({ label: `${cartridge.name}`, value: cartridge.id })
})
}
const addCartridgeName = async () => {
if (cartridgeName.value === '') {
return
@@ -237,11 +251,10 @@ const addCartridgeName = async () => {
cartridgeName.value = ''
addCartridgeDialog.value = false
}
const add = async () => {
v$.value.$touch()
if (v$.value.$invalid || !file.value) {
if (v$.value.$invalid || (!route.params.id && !file.value)) {
toast.add({
severity: 'error',
summary: 'Error',
@@ -252,6 +265,12 @@ const add = async () => {
return
}
let id = ""
if (route.params.id) {
id = "/" + route.params.id.toString()
}
const formData = new FormData()
formData.append('bullet_id', load.value.bullet)
formData.append('cartridge_id', load.value.cartridge)
@@ -259,22 +278,43 @@ const add = async () => {
formData.append('powder_gr', load.value.powderGrs.toString())
formData.append('primer_id', load.value.primer)
formData.append('col', load.value.col)
if (file.value) {
formData.append('photo', file.value)
}
try {
const response = await axios.post<any, Response<string>>(`${import.meta.env.VITE_API}/load`, formData, {
const response = await axios.post<any, Response<string>>(`${import.meta.env.VITE_API}/load${id}`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
const message = route.params.id ? 'Load updated' : 'Load added'
toast.add({
severity: 'success',
summary: 'Success',
detail: 'Load added',
detail: message,
life: 3000,
})
if (route.params.id) {
load.value = {
bullet: '',
cartridge: '',
powder: '',
powderGrs: 0,
primer: '',
col: '',
}
file.value = null
v$.value.$reset()
await fetchLoad()
return
}
await router.push(`/loads/edit/${response.data.payload}`)
} catch (error) {
toast.add({
@@ -284,14 +324,85 @@ const add = async () => {
life: 3000,
})
}
}
const deleteLoad = async () => {
if (!route.params.id) {
return
}
try {
await axios.delete(`${import.meta.env.VITE_API}/load/${route.params.id}`)
toast.add({
severity: 'success',
summary: 'Success',
detail: 'Load deleted',
life: 3000,
})
await router.push('/loads/search')
} catch (error) {
toast.add({
severity: 'error',
summary: 'Error',
detail: 'Error deleting load',
life: 3000,
})
}
}
const fetchLoad = async () => {
if (!route.params.id) {
return
}
loading.value = true
const response = await axios.get<any, Response<Load>>(`${import.meta.env.VITE_API}/load/${route.params.id}`)
if (response.data.payload) {
load.value.cartridge = response.data.payload.cartridge_id
load.value.bullet = response.data.payload.bullet.id
load.value.powder = response.data.payload.powder.id
load.value.powderGrs = response.data.payload.powder_gr
load.value.primer = response.data.payload.primer.id
load.value.col = response.data.payload.col.toString()
if (!load.value.col.includes('.')) {
load.value.col = `${load.value.col}.000`
} else {
const parts = load.value.col.split('.')
if (parts[1].length < 3) {
load.value.col = `${parts[0]}.${parts[1].padEnd(3, '0')}`
}
}
calcUrl()
} else {
toast.add({
severity: 'error',
summary: 'Error',
detail: 'Load not found',
life: 3000,
})
await router.push('/loads')
}
loading.value = false
}
onMounted(() => {
fetchBullets()
fetchPrimers()
fetchPowders()
fetchCartridges()
if (route.params.id) {
setTimeout(() => {
fetchLoad()
}, 100)
}
})
</script>

View File

@@ -8,13 +8,15 @@
:value="loads"
filterDisplay="row"
paginator
:rowsPerPageOptions="[5, 10, 20, 50]"
size="small"
:sortField="sortField"
:sortOrder="sortOrder"
@update:sortField="(e: string) => {sortField = e; fetchLoads()}"
@update:sortOrder="(e: number | undefined) => {sortOrder = e; fetchLoads()}"
@page="updatePagination"
:rows="rowsPerPage"
lazy
:rows="50"
:totalRecords="total"
:loading="loading"
>
@@ -42,7 +44,9 @@
@change="fetchLoads" />
</template>
<template #body="{ data }">
<a target="_blank" :href="data.bullet.manufacturer.url">
{{ data.bullet.manufacturer.name }}
</a>
</template>
</Column>
<Column field="bullet_name" header="Bullet" :sortable="true" :showFilterMenu="false">
@@ -63,7 +67,9 @@
@change="fetchLoads" />
</template>
<template #body="{ data }">
<a target="_blank" :href="data.primer.manufacturer.url">
{{ data.primer.manufacturer.name }}
</a>
</template>
</Column>
<Column field="primer_name" header="Primer" :sortable="true" :showFilterMenu="false">
@@ -83,7 +89,9 @@
@change="fetchLoads" />
</template>
<template #body="{ data }">
<a target="_blank" :href="data.powder.manufacturer.url">
{{ data.powder.manufacturer.name }}
</a>
</template>
</Column>
@@ -104,8 +112,13 @@
</Column>
<Column field="edit" header="Edit">
<template #body>
<Button size="small" text :icon="icons.edit" />
<template #body="{ data }">
<Button
size="small"
text
:icon="icons.edit"
@click="router.push('/loads/edit/' + data.id)"
/>
</template>
</Column>
</DataTable>
@@ -116,22 +129,13 @@
import { Bullet } from '../../types/bullet'
import { Powder } from '../../types/powder'
import { Primers } from '../../types/primers'
import { Load } from '../../types/Response'
interface LoadResponse {
total: number
results: Load[]
}
interface Load {
id: string
bullet: Bullet
cartridge: string
powder: Powder
powder_gr: number
primer: Primers
col: number
}
interface Option {
label: string
value: string
@@ -143,6 +147,7 @@ import { Response } from '../../types/Response'
import axios from 'axios'
import Column from 'primevue/column'
import { icons } from '../../lib/icons.ts'
import router from '../../router'
const DataTable = defineAsyncComponent(() => import('primevue/datatable'))
const Card = defineAsyncComponent(() => import('primevue/card'))
@@ -151,6 +156,8 @@ const MultiSelect = defineAsyncComponent(() => import('primevue/multiselect'))
const loads = ref<Load[]>([])
const total = ref(0)
const rowsPerPage = ref(50)
const page = ref(1)
const loading = ref(true)
// use local storage to store the selected filters
@@ -181,6 +188,14 @@ const powderManufacturerSelected = ref<string[]>(localStorageFilters.powderManuf
const powderOptions = ref<Option[]>([])
const powderSelected = ref<string[]>(localStorageFilters.powderSelected ?? [])
const updatePagination = (e: { page: number, rows: number }) => {
console.log(e)
page.value = e.page + 1
rowsPerPage.value = e.rows
fetchLoads()
}
const fetchLoads = async () => {
loading.value = true
@@ -220,6 +235,9 @@ const fetchLoads = async () => {
searchParams.unshift(`powder_id=${powderSelected.value.join(',')}`)
}
searchParams.unshift(`limit=${rowsPerPage.value}`)
searchParams.unshift(`page=${page.value}`)
localStorage.setItem(localStorageKey, JSON.stringify({
cartridgeSelected: cartridgeSelected.value,
bulletManufacturerSelected: bulletManufacturerSelected.value,
@@ -257,6 +275,11 @@ onMounted(() => {
value: bullet.manufacturer.id,
}))
// dedupe the bullet Manufacturer options
bulletManufacturerOptions.value = bulletManufacturerOptions.value.filter((option, index, self) =>
index === self.findIndex((o) => o.value === option.value)
)
bulletOptions.value = resp.data.payload.map((bullet) => ({
label: `${bullet.name} ${bullet.weight}gr .${bullet.diameter}`,
value: bullet.id,
@@ -269,6 +292,11 @@ onMounted(() => {
value: primer.manufacturer.id,
}))
// dedupe the primer Manufacturer options
primerManufacturerOptions.value = primerManufacturerOptions.value.filter((option, index, self) =>
index === self.findIndex((o) => o.value === option.value)
)
primerOptions.value = resp.data.payload.map((primer) => ({
label: primer.name,
value: primer.id,
@@ -281,6 +309,11 @@ onMounted(() => {
value: powder.manufacturer.id,
}))
// dedupe the powder Manufacturer options
powderManufacturerOptions.value = powderManufacturerOptions.value.filter((option, index, self) =>
index === self.findIndex((o) => o.value === option.value)
)
powderOptions.value = resp.data.payload.map((powder) => ({
label: powder.name,
value: powder.id,

View File

@@ -61,6 +61,10 @@ const routes = [
path: '/loads/search',
component: () => import('../pages/loads/Search.vue'),
},
{
path: '/loads/edit/:id',
component: () => import('../pages/loads/Add.vue'),
},
] as RouteRecordRaw[]
const router = createRouter({

View File

@@ -1,4 +1,18 @@
import {AxiosResponse} from "axios";
import { Bullet } from './bullet'
import { Powder } from './powder'
import { Primers } from './primers'
interface Load {
id: string
bullet: Bullet
cartridge: string
cartridge_id: string
powder: Powder
powder_gr: number
primer: Primers
col: number
}
export interface Response<T> extends AxiosResponse {
data: {