- Dockerfile: استفاده از Nexus Docker (194.5.195.53:32082) - NuGet.config: استفاده از Nexus NuGet با HTTP و allowInsecureConnections - workflow: حذف kubectl dependency، اضافه کردن 32082 به insecure-registries
This commit is contained in:
@@ -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 }}"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
<clear />
|
||||
<!-- Nexus as primary source (proxies nuget.org + caches packages) -->
|
||||
<add key="Nexus" value="http://194.5.195.53:32081/repository/nuget-all/index.json" allowInsecureConnections="true" />
|
||||
<!-- Backup: Direct Gitea registries -->
|
||||
<add key="FourSat" value="https://git.afrino.co/api/packages/FourSat/nuget/index.json" />
|
||||
<add key="Afrino" value="https://git.afrino.co/api/packages/Afrino/nuget/index.json" />
|
||||
</packageSources>
|
||||
<packageSourceCredentials>
|
||||
<Nexus>
|
||||
<add key="Username" value="admin" />
|
||||
<add key="ClearTextPassword" value="87zH26nbqT" />
|
||||
</Nexus>
|
||||
<FourSat>
|
||||
<add key="Username" value="masoud" />
|
||||
<add key="ClearTextPassword" value="87zH26nbqT" />
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
@using BackOffice.Services.DiscountCategory
|
||||
|
||||
<MudSelect @ref="_selectRef"
|
||||
T="long"
|
||||
MultiSelection="true"
|
||||
SelectedValues="_internalSelectedIds"
|
||||
SelectedValuesChanged="OnSelectedValuesChangedAsync"
|
||||
Label="@Label"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense"
|
||||
Disabled="@Disabled">
|
||||
@foreach (var item in _items)
|
||||
{
|
||||
<MudSelectItem Value="@item.Id">@item.Title</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
@@ -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<long> SelectedIds { get; set; } = new();
|
||||
[Parameter] public EventCallback<List<long>> SelectedIdsChanged { get; set; }
|
||||
[Parameter] public string? Label { get; set; } = "انتخاب دستهبندیها";
|
||||
[Parameter] public bool Disabled { get; set; }
|
||||
|
||||
private List<DiscountCategoryDto> _items = new();
|
||||
private HashSet<long> _internalSelectedIds = new();
|
||||
private MudSelect<long>? _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<DiscountCategoryDto>());
|
||||
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<DiscountCategoryDto>();
|
||||
}
|
||||
}
|
||||
|
||||
private List<DiscountCategoryDto> FlattenCategories(List<DiscountCategoryDto> categories, string prefix = "")
|
||||
{
|
||||
var result = new List<DiscountCategoryDto>();
|
||||
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<long>();
|
||||
}
|
||||
|
||||
private async Task OnSelectedValuesChangedAsync(IEnumerable<long> values)
|
||||
{
|
||||
_internalSelectedIds = values.Where(id => id > 0).Distinct().ToHashSet();
|
||||
SelectedIds = _internalSelectedIds.ToList();
|
||||
|
||||
if (SelectedIdsChanged.HasDelegate)
|
||||
{
|
||||
await SelectedIdsChanged.InvokeAsync(SelectedIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Tizzani.MudBlazor.HtmlEditor
|
||||
@using BackOffice.Common.BaseComponents
|
||||
@using BackOffice.Pages.AutoComplete
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
<MudDialog>
|
||||
@@ -111,23 +112,13 @@
|
||||
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.subtitle2">دستهبندیها</MudText>
|
||||
<MudSelect @bind-SelectedValues="_selectedCategoryIds"
|
||||
Label="انتخاب دستهبندیها"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense"
|
||||
MultiSelection="true"
|
||||
MultiSelectionTextFunc="@(new Func<List<string>, string>(GetMultiSelectionText))"
|
||||
Disabled="_loading"
|
||||
T="long">
|
||||
@foreach (var category in _categories)
|
||||
{
|
||||
<MudSelectItem Value="@category.Id">@category.Title</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
@if (_selectedCategoryIds?.Any() == true)
|
||||
<DiscountCategoryMultiSelectCombo @bind-SelectedIds="_selectedCategoryIds"
|
||||
Label="انتخاب دستهبندیها"
|
||||
Disabled="_loading" />
|
||||
@if (_selectedCategoryIds?.Count > 0)
|
||||
{
|
||||
<MudText Typo="Typo.caption">
|
||||
تعداد دستهبندیهای انتخابشده: @_selectedCategoryIds.Count()
|
||||
تعداد دستهبندیهای انتخابشده: @_selectedCategoryIds.Count
|
||||
</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
@@ -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<long> _selectedCategoryIds = new List<long>();
|
||||
private List<DiscountCategoryDto> _categories = new();
|
||||
private List<long> _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<DiscountCategoryDto> FlattenCategories(List<DiscountCategoryDto> categories, string prefix = "")
|
||||
{
|
||||
var result = new List<DiscountCategoryDto>();
|
||||
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<string> selectedValues)
|
||||
{
|
||||
if (selectedValues == null || !selectedValues.Any())
|
||||
return "دستهبندی انتخاب نشده";
|
||||
|
||||
return $"{selectedValues.Count} دستهبندی انتخاب شده";
|
||||
return base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
private async Task OnMainImageSelected(IBrowserFile? file)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user