From: Shane Jaroch Date: Wed, 21 Jan 2026 20:34:29 +0000 (-0500) Subject: version/release workflows. ui updates X-Git-Url: https://git.nutra.tk/v2?a=commitdiff_plain;h=95540d877125abc390a4f2cd4be8c190e6ef29ea;p=nutratech%2Fgui.git version/release workflows. ui updates --- diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ef4c207 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,176 @@ +name: Release Build + +on: + push: + tags: + - "v*" + +jobs: + build-linux-20-04: + name: "Linux (Ubuntu 20.04)" + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y git cmake build-essential \ + qtbase5-dev libqt5sql5-sqlite libgl1-mesa-dev + + - name: Build + run: make release + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: nutra-linux-20.04 + path: build/nutra + + build-linux-22-04: + name: "Linux (Ubuntu 22.04)" + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y git cmake build-essential \ + qt6-base-dev libqt6sql6 libqt6sql6-sqlite libgl1-mesa-dev + + - name: Build + run: make release + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: nutra-linux-22.04 + path: build/nutra + + build-linux-24-04: + name: "Linux (Ubuntu 24.04)" + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y git cmake build-essential \ + qt6-base-dev libqt6sql6 libqt6sql6-sqlite libgl1-mesa-dev + + - name: Build + run: make release + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: nutra-linux-24.04 + path: build/nutra + + build-windows: + name: "Windows" + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + version: "6.5.0" + host: "windows" + + - name: Build + run: make release + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: nutra-win64.exe + path: build/Release/nutra.exe + + build-macos: + name: "macOS" + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + version: "6.5.0" + host: "mac" + + - name: Build + run: make release + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: nutra-macos.app + path: build/nutra.app + + release: + name: "Create Release" + needs: + [ + build-linux-20-04, + build-linux-22-04, + build-linux-24-04, + build-windows, + build-macos, + ] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Verify tag is on master + run: | + git fetch origin master + if ! git merge-base --is-ancestor ${{ github.ref_name }} origin/master; then + echo "Error: Tag ${{ github.ref_name }} is not on master branch." + exit 1 + fi + + - name: Check for Pre-release + id: check_prerelease + run: | + if [[ "${{ github.ref_name }}" == *"-"* ]]; then + echo "is_prerelease=true" >> $GITHUB_OUTPUT + echo "Detected pre-release tag." + else + echo "is_prerelease=false" >> $GITHUB_OUTPUT + echo "Detected stable release tag." + fi + + - name: Download Artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Create Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + prerelease: ${{ steps.check_prerelease.outputs.is_prerelease }} + files: | + nutra-linux-20.04/nutra + nutra-linux-22.04/nutra + nutra-linux-24.04/nutra + nutra-win64.exe/nutra.exe + nutra-macos.app/** + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml index 2019c8e..1714614 100644 --- a/.github/workflows/version-bump.yml +++ b/.github/workflows/version-bump.yml @@ -1,10 +1,10 @@ -name: Manual Version Bump +name: Bump Version on: workflow_dispatch: inputs: bump_type: - description: "Type of bump" + description: "How to bump version" required: true default: "patch" type: choice @@ -12,54 +12,89 @@ on: - patch - minor - major + pre_release_type: + description: "Pre-release type (optional)" + required: false + default: "none" + type: choice + options: + - none + - beta + - rc jobs: - bump: + bump-version: runs-on: ubuntu-latest - permissions: - contents: write steps: - uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.GITHUB_TOKEN }} - - name: Configure Git + - name: Git Config run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Calculate and Push New Tag + - name: Bump Version run: | - # Get current tag - CURRENT_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") - echo "Current tag: $CURRENT_TAG" + # Get latest tag, remove 'v' prefix + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") + # Remove v prefix + VERSION=${LATEST_TAG#v} + + # Parse current version + BASE_VERSION=$(echo "$VERSION" | cut -d'-' -f1) + PRERELEASE_PART=$(echo "$VERSION" | cut -d'-' -f2- -s) - # Remove 'v' prefix - VERSION=${CURRENT_TAG#v} + IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE_VERSION" - # Split version - IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION" + BUMP_TYPE="${{ inputs.bump_type }}" + PRE_TYPE="${{ inputs.pre_release_type }}" - # Calculate next version - case "${{ inputs.bump_type }}" in - major) - MAJOR=$((MAJOR + 1)) - MINOR=0 - PATCH=0 - ;; - minor) - MINOR=$((MINOR + 1)) - PATCH=0 - ;; - patch) + # If currently no prerelease part, simple bump logic or start new prerelease + if [ -z "$PRERELEASE_PART" ]; then + if [ "$BUMP_TYPE" == "major" ]; then + MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 + elif [ "$BUMP_TYPE" == "minor" ]; then + MINOR=$((MINOR + 1)); PATCH=0 + else PATCH=$((PATCH + 1)) - ;; - esac + fi + + if [ "$PRE_TYPE" != "none" ]; then + NEW_TAG="v$MAJOR.$MINOR.$PATCH-$PRE_TYPE.1" + else + NEW_TAG="v$MAJOR.$MINOR.$PATCH" + fi + else + # Existing prerelease (e.g., 1.0.0-beta.1) + # Check if we are switching pre-release type or completing it + CURRENT_PRE_TYPE=$(echo "$PRERELEASE_PART" | cut -d'.' -f1) + CURRENT_PRE_NUM=$(echo "$PRERELEASE_PART" | cut -d'.' -f2) + + if [ "$PRE_TYPE" == "none" ]; then + # Promotion to stable: 1.0.0-beta.1 -> 1.0.0 + # Keep same MAJOR.MINOR.PATCH + NEW_TAG="v$MAJOR.$MINOR.$PATCH" + elif [ "$PRE_TYPE" == "$CURRENT_PRE_TYPE" ]; then + # Increment same prerelease type: 1.0.0-beta.1 -> 1.0.0-beta.2 + NEW_NUM=$((CURRENT_PRE_NUM + 1)) + NEW_TAG="v$MAJOR.$MINOR.$PATCH-$PRE_TYPE.$NEW_NUM" + else + # Switching type, restart count? e.g. beta.2 -> rc.1 + NEW_TAG="v$MAJOR.$MINOR.$PATCH-$PRE_TYPE.1" + fi + + # Note: If user explicitly requested BUMP_TYPE (major/minor/patch) on a pre-release, + # this logic might need refinement, but standard flow is: + # 1. Bump to new version (potentially starting beta) + # 2. Iterate on beta + # 3. Promote to stable (none) + fi - NEW_TAG="v$MAJOR.$MINOR.$PATCH" - echo "New tag: $NEW_TAG" + echo "Bumping from $LATEST_TAG to $NEW_TAG" + echo "NEW_TAG=$NEW_TAG" >> $GITHUB_ENV - # Create and push tag - git tag "$NEW_TAG" - git push origin "$NEW_TAG" + git tag ${{ env.NEW_TAG }} + git push origin ${{ env.NEW_TAG }} diff --git a/include/db/foodrepository.h b/include/db/foodrepository.h index cb2d266..3a27f47 100644 --- a/include/db/foodrepository.h +++ b/include/db/foodrepository.h @@ -20,6 +20,7 @@ struct ServingWeight { struct FoodItem { int id; + int foodGroupId; QString description; QString foodGroupName; int nutrientCount; diff --git a/src/db/foodrepository.cpp b/src/db/foodrepository.cpp index 05d4d32..646d195 100644 --- a/src/db/foodrepository.cpp +++ b/src/db/foodrepository.cpp @@ -24,7 +24,7 @@ void FoodRepository::ensureCacheLoaded() { // 1. Load Food Items with Group Names QSqlQuery query( - "SELECT f.id, f.long_desc, g.fdgrp_desc " + "SELECT f.id, f.long_desc, g.fdgrp_desc, f.fdgrp_id " "FROM food_des f " "JOIN fdgrp g ON f.fdgrp_id = g.id", db); @@ -41,6 +41,7 @@ void FoodRepository::ensureCacheLoaded() { item.id = query.value(0).toInt(); item.description = query.value(1).toString(); item.foodGroupName = query.value(2).toString(); + item.foodGroupId = query.value(3).toInt(); // Set counts from map (default 0 if not found) auto it = nutrientCounts.find(item.id); diff --git a/src/widgets/dailylogwidget.cpp b/src/widgets/dailylogwidget.cpp index 40b0cc5..b0b9870 100644 --- a/src/widgets/dailylogwidget.cpp +++ b/src/widgets/dailylogwidget.cpp @@ -15,11 +15,11 @@ DailyLogWidget::DailyLogWidget(QWidget* parent) : QWidget(parent) { void DailyLogWidget::setupUi() { auto* mainLayout = new QVBoxLayout(this); - QSplitter* splitter = new QSplitter(Qt::Vertical, this); + auto* splitter = new QSplitter(Qt::Vertical, this); mainLayout->addWidget(splitter); // --- Top: Log Table --- - QWidget* topWidget = new QWidget(this); + auto* topWidget = new QWidget(this); auto* topLayout = new QVBoxLayout(topWidget); topLayout->setContentsMargins(0, 0, 0, 0); topLayout->addWidget(new QLabel("Today's Food Log", this)); @@ -33,11 +33,11 @@ void DailyLogWidget::setupUi() { splitter->addWidget(topWidget); // --- Bottom: Analysis --- - QWidget* bottomWidget = new QWidget(this); + auto* bottomWidget = new QWidget(this); auto* bottomLayout = new QVBoxLayout(bottomWidget); bottomLayout->setContentsMargins(0, 0, 0, 0); - QGroupBox* analysisBox = new QGroupBox("Analysis (Projected)", this); + auto* analysisBox = new QGroupBox("Analysis (Projected)", this); auto* analysisLayout = new QVBoxLayout(analysisBox); // Analysis UI diff --git a/src/widgets/searchwidget.cpp b/src/widgets/searchwidget.cpp index 8168310..a4a0b80 100644 --- a/src/widgets/searchwidget.cpp +++ b/src/widgets/searchwidget.cpp @@ -64,8 +64,42 @@ void SearchWidget::performSearch() { for (int i = 0; i < static_cast(results.size()); ++i) { const auto& item = results[i]; resultsTable->setItem(i, 0, new QTableWidgetItem(QString::number(item.id))); - resultsTable->setItem(i, 1, new QTableWidgetItem(item.description)); - resultsTable->setItem(i, 2, new QTableWidgetItem(item.foodGroupName)); + static const std::map groupAbbreviations = { + {1100, "Vegetables"}, // Vegetables and Vegetable Products + {600, "Soups/Sauces"}, // Soups, Sauces, and Gravies + {1700, "Lamb/Veal/Game"}, // Lamb, Veal, and Game Products + {500, "Poultry"}, // Poultry Products + {700, "Sausages/Meats"}, // Sausages and Luncheon Meats + {800, "Cereals"}, // Breakfast Cereals + {900, "Fruits"}, // Fruits and Fruit Juices + {1200, "Nuts/Seeds"}, // Nut and Seed Products + {1400, "Beverages"}, // Beverages + {400, "Fats/Oils"}, // Fats and Oils + {1900, "Sweets"}, // Sweets + {1800, "Baked Prod."}, // Baked Products + {2100, "Fast Food"}, // Fast Foods + {2200, "Meals/Entrees"}, // Meals, Entrees, and Side Dishes + {2500, "Snacks"}, // Snacks + {3600, "Restaurant"}, // Restaurant Foods + {100, "Dairy/Egg"}, // Dairy and Egg Products + {1300, "Beef"}, // Beef Products + {1000, "Pork"}, // Pork Products + {2000, "Grains/Pasta"}, // Cereal Grains and Pasta + {1600, "Legumes"}, // Legumes and Legume Products + {1500, "Fish/Shellfish"}, // Finfish and Shellfish Products + {300, "Baby Food"}, // Baby Foods + {200, "Spices"}, // Spices and Herbs + {3500, "Native Foods"} // American Indian/Alaska Native Foods + }; + + QString group = item.foodGroupName; + auto it = groupAbbreviations.find(item.foodGroupId); + if (it != groupAbbreviations.end()) { + group = it->second; + } else if (group.length() > 20) { + group = group.left(17) + "..."; + } + resultsTable->setItem(i, 2, new QTableWidgetItem(group)); resultsTable->setItem(i, 3, new QTableWidgetItem(QString::number(item.nutrientCount))); resultsTable->setItem(i, 4, new QTableWidgetItem(QString::number(item.aminoCount))); resultsTable->setItem(i, 5, new QTableWidgetItem(QString::number(item.flavCount)));