From 8a285e485b74d838f8ae86ee3a1d06a669380f74 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Thu, 29 Jan 2026 02:56:20 +0330 Subject: [PATCH] =?UTF-8?q?chore:=20=D8=AA=D9=86=D8=B8=DB=8C=D9=85=20Nexus?= =?UTF-8?q?=20=D8=A8=D8=B1=D8=A7=DB=8C=20NuGet=20=D9=88=20Docker=20offline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Dockerfile: استفاده از Nexus Docker (194.5.195.53:32082) - NuGet.config: استفاده از Nexus NuGet با HTTP و allowInsecureConnections - workflow: حذف kubectl dependency، اضافه کردن 32082 به insecure-registries --- .gitea/workflows/kub-deploy.yml | 56 +++------- .gitea/workflows/prod-deploy.yml | 6 +- src/BackOffice/Dockerfile | 2 +- src/BackOffice/NuGet.config | 9 +- .../DiscountCategoryMultiSelectCombo.razor | 16 +++ .../DiscountCategoryMultiSelectCombo.razor.cs | 105 ++++++++++++++++++ .../Components/ProductFormDialog.razor | 79 ++----------- .../DiscountProductsMainPage.razor | 14 ++- .../DiscountCategoryService.cs | 2 + .../DiscountProduct/DiscountProductService.cs | 5 + 10 files changed, 180 insertions(+), 114 deletions(-) create mode 100644 src/BackOffice/Pages/AutoComplete/DiscountCategoryMultiSelectCombo.razor create mode 100644 src/BackOffice/Pages/AutoComplete/DiscountCategoryMultiSelectCombo.razor.cs diff --git a/.gitea/workflows/kub-deploy.yml b/.gitea/workflows/kub-deploy.yml index 1d95eb3..16d0153 100644 --- a/.gitea/workflows/kub-deploy.yml +++ b/.gitea/workflows/kub-deploy.yml @@ -15,45 +15,27 @@ jobs: container: image: docker:latest options: --privileged - env: - HTTP_PROXY: http://proxyuser:87zH26nbqT2@46.249.98.211:3128 - HTTPS_PROXY: http://proxyuser:87zH26nbqT2@46.249.98.211:3128 - NO_PROXY: localhost,127.0.0.1,gitea-svc,194.5.195.53,10.0.0.0/8 steps: - - name: Install dependencies - run: | - apk add --no-cache git curl - - # Install kubectl - curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x kubectl - mv kubectl /usr/local/bin/ - - name: Start Docker daemon with insecure registry run: | mkdir -p /etc/docker cat > /etc/docker/daemon.json << 'DAEMON' { - "insecure-registries": ["194.5.195.53:30080", "gitea-svc:3000"] + "insecure-registries": ["194.5.195.53:30080", "194.5.195.53:32500", "194.5.195.53:32082", "gitea-svc:3000"], + "dns": ["0.0.0.0"] } DAEMON - mkdir -p ~/.docker - cat > ~/.docker/config.json << 'CONF' - { - "proxies": { - "default": { - "httpProxy": "http://proxyuser:87zH26nbqT2@46.249.98.211:3128", - "httpsProxy": "http://proxyuser:87zH26nbqT2@46.249.98.211:3128", - "noProxy": "localhost,127.0.0.1,gitea-svc,194.5.195.53,10.0.0.0/8" - } - } - } - CONF + + # بدون اینترنت - استفاده از local registry dockerd & for i in $(seq 1 30); do docker info >/dev/null 2>&1 && break || sleep 2 done docker info + + # بررسی دسترسی به local registry + echo "📊 Checking local registry..." + nc -zv 194.5.195.53 32500 || echo "⚠️ WARNING: Cannot connect to local registry!" - name: Checkout code run: | @@ -63,11 +45,10 @@ jobs: - name: Build Docker Image run: | cd src - docker build -f BackOffice/Dockerfile \ + # استفاده از cached base images (بدون دانلود) + DOCKER_BUILDKIT=0 docker build -f BackOffice/Dockerfile \ -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \ -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \ - --build-arg HTTP_PROXY=http://proxyuser:87zH26nbqT2@46.249.98.211:3128 \ - --build-arg HTTPS_PROXY=http://proxyuser:87zH26nbqT2@46.249.98.211:3128 \ . @@ -77,14 +58,11 @@ jobs: docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - - name: Deploy to Kubernetes + - name: Build and Push Complete run: | - # Setup kubeconfig - mkdir -p ~/.kube - echo "${{ secrets.KUBECONFIG }}" | base64 -d > ~/.kube/config - - # Restart deployment to pull new image - kubectl rollout restart deployment/backoffice || echo "Deployment doesn't exist yet" - - # Wait for rollout to complete - kubectl rollout status deployment/backoffice --timeout=5m || echo "Deployment rollout pending" + echo "🎉 Build and push completed successfully!" + echo "📦 Image pushed to: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" + echo "📦 Latest tag: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + echo "" + echo "🚀 To deploy manually on server:" + echo "kubectl set image deployment/backoffice backoffice=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" diff --git a/.gitea/workflows/prod-deploy.yml b/.gitea/workflows/prod-deploy.yml index 4f9b9dc..4cd18ba 100644 --- a/.gitea/workflows/prod-deploy.yml +++ b/.gitea/workflows/prod-deploy.yml @@ -24,7 +24,9 @@ jobs: - name: Install dependencies run: | apk add --no-cache git curl - curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + # Install kubectl with fixed version + KUBECTL_VERSION="v1.31.0" + curl -LO "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl" chmod +x kubectl mv kubectl /usr/local/bin/ @@ -33,7 +35,7 @@ jobs: mkdir -p /etc/docker cat > /etc/docker/daemon.json << 'DAEMON' { - "insecure-registries": ["194.5.195.53:30080", "gitea-svc:3000"] + "insecure-registries": ["194.5.195.53:30080", "194.5.195.53:32082", "gitea-svc:3000"] } DAEMON mkdir -p ~/.docker diff --git a/src/BackOffice/Dockerfile b/src/BackOffice/Dockerfile index d053cef..faa6fe2 100644 --- a/src/BackOffice/Dockerfile +++ b/src/BackOffice/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM 194.5.195.53:32082/dotnet/sdk:9.0 AS build WORKDIR /src # Copy NuGet config and project file diff --git a/src/BackOffice/NuGet.config b/src/BackOffice/NuGet.config index 81da29b..4861568 100644 --- a/src/BackOffice/NuGet.config +++ b/src/BackOffice/NuGet.config @@ -1,11 +1,18 @@ - + + + + + + + + diff --git a/src/BackOffice/Pages/AutoComplete/DiscountCategoryMultiSelectCombo.razor b/src/BackOffice/Pages/AutoComplete/DiscountCategoryMultiSelectCombo.razor new file mode 100644 index 0000000..0647b5c --- /dev/null +++ b/src/BackOffice/Pages/AutoComplete/DiscountCategoryMultiSelectCombo.razor @@ -0,0 +1,16 @@ +@using BackOffice.Services.DiscountCategory + + + @foreach (var item in _items) + { + @item.Title + } + diff --git a/src/BackOffice/Pages/AutoComplete/DiscountCategoryMultiSelectCombo.razor.cs b/src/BackOffice/Pages/AutoComplete/DiscountCategoryMultiSelectCombo.razor.cs new file mode 100644 index 0000000..9a9e192 --- /dev/null +++ b/src/BackOffice/Pages/AutoComplete/DiscountCategoryMultiSelectCombo.razor.cs @@ -0,0 +1,105 @@ +using BackOffice.Services.DiscountCategory; +using Microsoft.AspNetCore.Components; +using MudBlazor; + +namespace BackOffice.Pages.AutoComplete; + +public partial class DiscountCategoryMultiSelectCombo +{ + [Inject] public IDiscountCategoryService CategoryService { get; set; } = default!; + + [Parameter] public List SelectedIds { get; set; } = new(); + [Parameter] public EventCallback> SelectedIdsChanged { get; set; } + [Parameter] public string? Label { get; set; } = "انتخاب دسته‌بندی‌ها"; + [Parameter] public bool Disabled { get; set; } + + private List _items = new(); + private HashSet _internalSelectedIds = new(); + private MudSelect? _selectRef; + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + await LoadCategoriesAsync(); + SyncInternalFromParameter(); + } + + protected override Task OnParametersSetAsync() + { + SyncInternalFromParameter(); + return base.OnParametersSetAsync(); + } + + private async Task LoadCategoriesAsync() + { + try + { + Console.WriteLine("Starting to load DiscountCategories..."); + var tree = await CategoryService.GetCategoriesAsync(isActive: true); + Console.WriteLine($"Received {tree?.Count ?? 0} root categories"); + _items = FlattenCategories(tree ?? new List()); + Console.WriteLine($"DiscountCategory loaded: {_items.Count} items"); + + // Log first few items + if (_items.Count > 0) + { + Console.WriteLine("Sample categories:"); + foreach (var item in _items.Take(5)) + { + Console.WriteLine($" - {item.Id}: {item.Title} (Active: {item.IsActive})"); + } + } + } + catch (Exception ex) + { + Console.WriteLine($"Error loading DiscountCategories: {ex.GetType().Name} - {ex.Message}"); + if (ex.InnerException != null) + { + Console.WriteLine($"Inner Exception: {ex.InnerException.Message}"); + } + Console.WriteLine($"Stack Trace: {ex.StackTrace}"); + _items = new List(); + } + } + + private List FlattenCategories(List categories, string prefix = "") + { + var result = new List(); + foreach (var category in categories) + { + var catCopy = new DiscountCategoryDto + { + Id = category.Id, + Title = prefix + category.Title, + Name = category.Name, + ParentCategoryId = category.ParentCategoryId, + IsActive = category.IsActive + }; + result.Add(catCopy); + + if (category.Children?.Any() == true) + { + result.AddRange(FlattenCategories(category.Children.ToList(), prefix + " ")); + } + } + return result; + } + + private void SyncInternalFromParameter() + { + _internalSelectedIds = SelectedIds != null + ? SelectedIds.Where(id => id > 0).Distinct().ToHashSet() + : new HashSet(); + } + + private async Task OnSelectedValuesChangedAsync(IEnumerable values) + { + _internalSelectedIds = values.Where(id => id > 0).Distinct().ToHashSet(); + SelectedIds = _internalSelectedIds.ToList(); + + if (SelectedIdsChanged.HasDelegate) + { + await SelectedIdsChanged.InvokeAsync(SelectedIds); + } + } +} diff --git a/src/BackOffice/Pages/DiscountShop/Components/ProductFormDialog.razor b/src/BackOffice/Pages/DiscountShop/Components/ProductFormDialog.razor index 04ff380..c81c56b 100644 --- a/src/BackOffice/Pages/DiscountShop/Components/ProductFormDialog.razor +++ b/src/BackOffice/Pages/DiscountShop/Components/ProductFormDialog.razor @@ -3,6 +3,7 @@ @using Microsoft.AspNetCore.Components.Forms @using Tizzani.MudBlazor.HtmlEditor @using BackOffice.Common.BaseComponents +@using BackOffice.Pages.AutoComplete @inject ISnackbar Snackbar @@ -111,23 +112,13 @@ دسته‌بندی‌ها - - @foreach (var category in _categories) - { - @category.Title - } - - @if (_selectedCategoryIds?.Any() == true) + + @if (_selectedCategoryIds?.Count > 0) { - تعداد دسته‌بندی‌های انتخاب‌شده: @_selectedCategoryIds.Count() + تعداد دسته‌بندی‌های انتخاب‌شده: @_selectedCategoryIds.Count } @@ -166,7 +157,6 @@ [CascadingParameter] IMudDialogInstance MudDialog { get; set; } = null!; [Parameter] public ProductFormModel Model { get; set; } = new(); [Parameter] public bool IsEditMode { get; set; } - [Inject] private IDiscountCategoryService CategoryService { get; set; } = null!; private MudForm? _form; private bool _isValid; @@ -175,66 +165,15 @@ private IBrowserFile? _thumbnailImageFile; private readonly long _maxAllowedSize = (1024 * 1024) * 5; private string? _mainImagePreview; - private IEnumerable _selectedCategoryIds = new List(); - private List _categories = new(); + private List _selectedCategoryIds = new(); - protected override async Task OnInitializedAsync() + protected override Task OnInitializedAsync() { - await LoadCategories(); - if (Model.CategoryIds?.Any() == true) { _selectedCategoryIds = Model.CategoryIds; } - } - - private async Task LoadCategories() - { - try - { - var tree = await CategoryService.GetCategoriesAsync(isActive: true); - _categories = FlattenCategories(tree); - Console.WriteLine($"Loaded {_categories.Count} categories"); - } - catch (Exception ex) - { - Console.WriteLine($"Error loading categories: {ex}"); - Snackbar.Add($"خطا در بارگذاری دسته‌بندی‌ها: {ex.Message}", Severity.Error); - } - } - - private List FlattenCategories(List categories, string prefix = "") - { - var result = new List(); - foreach (var category in categories) - { - var catCopy = new DiscountCategoryDto - { - Id = category.Id, - Title = prefix + category.Title, - ParentCategoryId = category.ParentCategoryId - }; - result.Add(catCopy); - - if (category.Children.Any()) - { - result.AddRange(FlattenCategories(category.Children.ToList(), prefix + " ")); - } - } - return result; - } - - private string GetCategoryPath(DiscountCategoryDto category) - { - return category.Title; - } - - private string GetMultiSelectionText(List selectedValues) - { - if (selectedValues == null || !selectedValues.Any()) - return "دسته‌بندی انتخاب نشده"; - - return $"{selectedValues.Count} دسته‌بندی انتخاب شده"; + return base.OnInitializedAsync(); } private async Task OnMainImageSelected(IBrowserFile? file) diff --git a/src/BackOffice/Pages/DiscountShop/DiscountProductsMainPage.razor b/src/BackOffice/Pages/DiscountShop/DiscountProductsMainPage.razor index f723dcd..bed537f 100644 --- a/src/BackOffice/Pages/DiscountShop/DiscountProductsMainPage.razor +++ b/src/BackOffice/Pages/DiscountShop/DiscountProductsMainPage.razor @@ -184,10 +184,22 @@ _products = products; _totalCount = totalCount; _totalPages = totalPages; - Snackbar.Add("محصولات بارگذاری شدند", Severity.Success); + + Console.WriteLine($"Loaded {_products.Count} products, Total: {_totalCount}, Pages: {_totalPages}"); + + if (_products.Count > 0) + { + Snackbar.Add($"{_products.Count} محصول بارگذاری شد", Severity.Success); + } + else + { + Snackbar.Add("هیچ محصولی یافت نشد", Severity.Info); + } } catch (Exception ex) { + Console.WriteLine($"Error loading products: {ex.Message}"); + Console.WriteLine($"StackTrace: {ex.StackTrace}"); Snackbar.Add($"خطا در بارگذاری محصولات: {ex.Message}", Severity.Error); } finally diff --git a/src/BackOffice/Services/DiscountCategory/DiscountCategoryService.cs b/src/BackOffice/Services/DiscountCategory/DiscountCategoryService.cs index c013e09..7602b11 100644 --- a/src/BackOffice/Services/DiscountCategory/DiscountCategoryService.cs +++ b/src/BackOffice/Services/DiscountCategory/DiscountCategoryService.cs @@ -20,7 +20,9 @@ public class DiscountCategoryService : IDiscountCategoryService if (isActive.HasValue) request.IsActive = isActive.Value; + Console.WriteLine($"Calling GetDiscountCategoriesAsync with ParentCategoryId={parentCategoryId}, IsActive={isActive}"); var response = await _client.GetDiscountCategoriesAsync(request); + Console.WriteLine($"Received {response.Categories?.Count ?? 0} categories from BFF"); return MapCategories(response.Categories); } diff --git a/src/BackOffice/Services/DiscountProduct/DiscountProductService.cs b/src/BackOffice/Services/DiscountProduct/DiscountProductService.cs index 7f2b711..ac84a3c 100644 --- a/src/BackOffice/Services/DiscountProduct/DiscountProductService.cs +++ b/src/BackOffice/Services/DiscountProduct/DiscountProductService.cs @@ -36,8 +36,13 @@ public class DiscountProductService : IDiscountProductService if (filter.InStock.HasValue) request.InStock = filter.InStock.Value; + Console.WriteLine($"Calling BFF GetDiscountProductsAsync - Page: {request.PageNumber}, PageSize: {request.PageSize}"); + var response = await _client.GetDiscountProductsAsync(request); + Console.WriteLine($"BFF Response - Models count: {response.Models?.Count ?? 0}"); + Console.WriteLine($"BFF Response - TotalCount: {response.MetaData?.TotalCount ?? 0}"); + var products = response.Models.Select(p => new DiscountProductDto { Id = p.Id,