Update MgGrid reload logic, add IsProd env flag, doc fixes

- MgGridBase: call Reload after item changes to refresh grid view
- Add IsProd environment flag (FruitBankConst, IFruitBankDataControllerCommon, SignalRTags, client/server wiring)
- Logger DI: fix constructor param, default AppType to Web in configs and DI setup
- Docs: clarify MgGrid edit flow, editor requirements, companion component structure, and disposal logic
- Add PowerShell test command for EkaerTradeCardValidatorTests
This commit is contained in:
Loretta 2026-07-12 14:32:05 +02:00
parent d63310b4d9
commit a3604d7333
12 changed files with 56 additions and 12 deletions

File diff suppressed because one or more lines are too long

View File

@ -27,6 +27,30 @@ namespace FruitBank.Common.Server
/// </summary> /// </summary>
public const string PreOrderWindowEnd = "PreOrderWindowEnd"; public const string PreOrderWindowEnd = "PreOrderWindowEnd";
// ── Environment flag — method-only surface on purpose: no property to bind/serialize/read accidentally ──
private static bool? _isProd;
/// <summary>
/// Set once by the plugin startup after DB-catalog classification.
/// A second call with a different value throws — the flag cannot flip at runtime.
/// </summary>
public static void SetIsProd(bool isProd)
{
if (_isProd.HasValue && _isProd.Value != isProd)
throw new InvalidOperationException(
$"IsProd is already set to {_isProd.Value}; refusing to change it to {isProd}.");
_isProd = isProd;
}
/// <summary>
/// True = PROD database. Throws until SetIsProd ran — an uninitialized read must never return a default.
/// </summary>
public static bool IsProd()
=> _isProd ?? throw new InvalidOperationException(
"IsProd has not been initialized — SetIsProd must run at startup before any read.");
static FruitBankConst() static FruitBankConst()
{ {
ProjectId = Guid.Parse(ProjectIdString); ProjectId = Guid.Parse(ProjectIdString);

View File

@ -6,6 +6,9 @@ namespace FruitBank.Common.Server.Services.Loggers;
public class LoggerToLoggerApiController : Logger<LoggerToLoggerApiController> public class LoggerToLoggerApiController : Logger<LoggerToLoggerApiController>
{ {
public LoggerToLoggerApiController(params IAcLogWriterBase[] logWriters) : base(logWriters) // IEnumerable — a MS DI tömböt ("params IAcLogWriterBase[]") NEM tud feloldani (InvalidOperationException:
// Unable to resolve service for type 'IAcLogWriterBase[]'), amitől a LoggerSignalRHub aktiválása minden
// kliens-kapcsolódásnál elszállt, és a felküldött kliens-logok némán elvesztek.
public LoggerToLoggerApiController(IEnumerable<IAcLogWriterBase> logWriters) : base(logWriters.ToArray())
{ } { }
} }

View File

@ -111,6 +111,12 @@ public interface IFruitBankDataControllerCommon
Task<MgLoginModelResponse?> LoginMeasuringUser(MgLoginModelRequest loginModelRequest); Task<MgLoginModelResponse?> LoginMeasuringUser(MgLoginModelRequest loginModelRequest);
Task<List<Partner>?> ProcessAndSaveFullShippingJson(string fullShippingJson, int customerId); Task<List<Partner>?> ProcessAndSaveFullShippingJson(string fullShippingJson, int customerId);
/// <summary>
/// True if the server runs against the PROD database. The value is definite by construction
/// (an ambiguous DB catalog fails the server startup); consumers must fail closed on any error.
/// </summary>
public Task<bool> IsProdEnvironment();
public Task<List<GenericAttributeDto>?> GetGenericAttributeDtosByEntityIdAndKeyGroup(int productId, string keyGroup, int storeId); public Task<List<GenericAttributeDto>?> GetGenericAttributeDtosByEntityIdAndKeyGroup(int productId, string keyGroup, int storeId);
public Task<GenericAttributeDto?> AddGenericAttributeDto(GenericAttributeDto genericAttributeDto); public Task<GenericAttributeDto?> AddGenericAttributeDto(GenericAttributeDto genericAttributeDto);

View File

@ -131,6 +131,8 @@ public class SignalRTags : AcSignalRTags
public const int AuthenticateUser = 195; public const int AuthenticateUser = 195;
public const int RefreshToken = 200; public const int RefreshToken = 200;
public const int IsProdEnvironment = 210;
#region SendToClient #region SendToClient
public const int SendOrderChanged = 500; public const int SendOrderChanged = 500;
public const int SendOrderItemChanged = 501; public const int SendOrderItemChanged = 501;

View File

@ -58,6 +58,8 @@ namespace FruitBankHybrid.Shared.Services.SignalRs
public Task<List<MeasuringModel>?> GetMeasuringModels() => GetAllAsync<List<MeasuringModel>>(SignalRTags.GetMeasuringModels); public Task<List<MeasuringModel>?> GetMeasuringModels() => GetAllAsync<List<MeasuringModel>>(SignalRTags.GetMeasuringModels);
public Task<bool> IsProdEnvironment() => GetAllAsync<bool>(SignalRTags.IsProdEnvironment);
#region Partner #region Partner
public Task<List<Partner>?> GetPartners() => GetAllAsync<List<Partner>>(SignalRTags.GetPartners); public Task<List<Partner>?> GetPartners() => GetAllAsync<List<Partner>>(SignalRTags.GetPartners);
public Task<Partner?> GetPartnerById(int id) => GetByIdAsync<Partner?>(SignalRTags.GetPartnerById, id); public Task<Partner?> GetPartnerById(int id) => GetByIdAsync<Partner?>(SignalRTags.GetPartnerById, id);

View File

@ -14,7 +14,7 @@
//"ApiBaseUrl": "https://shop.fruitbank.hu" //"ApiBaseUrl": "https://shop.fruitbank.hu"
}, },
"Logger": { "Logger": {
"AppType": "Server", "AppType": "Web",
"LogLevel": "Detail", "LogLevel": "Detail",
"LogWriters": [ "LogWriters": [
{ {

View File

@ -1,3 +1,4 @@
using AyCode.Core.Enums;
using AyCode.Core.Loggers; using AyCode.Core.Loggers;
using AyCode.Core.Serializers.Binaries; using AyCode.Core.Serializers.Binaries;
using AyCode.Services.SignalRs; using AyCode.Services.SignalRs;
@ -43,9 +44,10 @@ builder.Services.Configure<AcBinaryHubProtocolOptions>(opts =>
}); });
// Logger options + framework factory. LoggerClient instances are created per caller category, // Logger options + framework factory. LoggerClient instances are created per caller category,
// with AppType+LogLevel from appsettings and writers resolved from DI via IAcLogWriterClientBase. // with LogLevel from appsettings and writers resolved from DI via IAcLogWriterClientBase.
// AppType: a WASM kliens kód-defaultja Web — az appsettings (AyCode:Logger:AppType) felülírhatja, ha megadja.
builder.Services.Configure<AcLoggerOptions>(builder.Configuration.GetSection("AyCode:Logger")); builder.Services.Configure<AcLoggerOptions>(builder.Configuration.GetSection("AyCode:Logger"));
builder.Services.AddAcLoggerFactory<LoggerClient, IAcLogWriterClientBase>(); builder.Services.AddAcLoggerFactory<LoggerClient, IAcLogWriterClientBase>(AppType.Web);
// HubConnectionBuilder — transient so each consumer gets a fresh builder to Build(). // HubConnectionBuilder — transient so each consumer gets a fresh builder to Build().
// All connection and protocol configuration flows from appsettings.json via IOptions<T>; // All connection and protocol configuration flows from appsettings.json via IOptions<T>;

View File

@ -14,7 +14,7 @@
//"ApiBaseUrl": "https://shop.fruitbank.hu" //"ApiBaseUrl": "https://shop.fruitbank.hu"
}, },
"Logger": { "Logger": {
"AppType": "Server", "AppType": "Web",
"LogLevel": "Detail", "LogLevel": "Detail",
"LogWriters": [ "LogWriters": [
{ {

View File

@ -1,3 +1,4 @@
using AyCode.Core.Enums;
using AyCode.Core.Loggers; using AyCode.Core.Loggers;
using AyCode.Core.Serializers.Binaries; using AyCode.Core.Serializers.Binaries;
using AyCode.Services.SignalRs; using AyCode.Services.SignalRs;
@ -26,9 +27,10 @@ builder.Services.AddSingleton<ISecureCredentialService, ServerSecureCredentialSe
builder.Services.AddSingleton<IAcLogWriterBase, ConsoleLogWriter>(); builder.Services.AddSingleton<IAcLogWriterBase, ConsoleLogWriter>();
// Logger options + framework factory. LoggerClient instances are created per caller category, // Logger options + framework factory. LoggerClient instances are created per caller category,
// with AppType+LogLevel from appsettings and writers resolved from DI via IAcLogWriterBase. // with LogLevel from appsettings and writers resolved from DI via IAcLogWriterBase.
// AppType: a hybrid WEB-host kód-defaultja Web (az [S] a nop-szerveré) — az appsettings felülírhatja, ha megadja.
builder.Services.Configure<AcLoggerOptions>(builder.Configuration.GetSection("AyCode:Logger")); builder.Services.Configure<AcLoggerOptions>(builder.Configuration.GetSection("AyCode:Logger"));
builder.Services.AddAcLoggerFactory<LoggerClient>(); builder.Services.AddAcLoggerFactory<LoggerClient>(AppType.Web);
builder.Services.AddSingleton<LoggedInModel>(sp => new LoggedInModel(sp.GetRequiredService<ISecureCredentialService>())); builder.Services.AddSingleton<LoggedInModel>(sp => new LoggedInModel(sp.GetRequiredService<ISecureCredentialService>()));

View File

@ -14,7 +14,7 @@
//"ApiBaseUrl": "https://shop.fruitbank.hu" //"ApiBaseUrl": "https://shop.fruitbank.hu"
}, },
"Logger": { "Logger": {
"AppType": "Server", "AppType": "Web",
"LogLevel": "Detail", "LogLevel": "Detail",
"LogWriters": [ "LogWriters": [
{ {

View File

@ -1,4 +1,5 @@
using AyCode.Core.Loggers; using AyCode.Core.Enums;
using AyCode.Core.Loggers;
using AyCode.Services.SignalRs; using AyCode.Services.SignalRs;
using FruitBank.Common.Loggers; using FruitBank.Common.Loggers;
using FruitBank.Common.Models; using FruitBank.Common.Models;
@ -51,9 +52,10 @@ namespace FruitBankHybrid
builder.Services.AddSingleton<IAcLogWriterClientBase, SignaRClientLogItemWriter>(); builder.Services.AddSingleton<IAcLogWriterClientBase, SignaRClientLogItemWriter>();
// Logger options + framework factory. LoggerClient instances are created per caller category, // Logger options + framework factory. LoggerClient instances are created per caller category,
// with AppType+LogLevel from appsettings and writers resolved from DI via IAcLogWriterClientBase. // with LogLevel from appsettings and writers resolved from DI via IAcLogWriterClientBase.
// AppType: a MAUI kliens kód-defaultja Web — az appsettings felülírhatja (pl. Mobile-ra), ha megadja.
builder.Services.Configure<AcLoggerOptions>(builder.Configuration.GetSection("AyCode:Logger")); builder.Services.Configure<AcLoggerOptions>(builder.Configuration.GetSection("AyCode:Logger"));
builder.Services.AddAcLoggerFactory<LoggerClient, IAcLogWriterClientBase>(); builder.Services.AddAcLoggerFactory<LoggerClient, IAcLogWriterClientBase>(AppType.Web);
// Bind SignalR options from configuration. // Bind SignalR options from configuration.
// Precedence: code default → appsettings.json (this line) → any later Configure<T> action. // Precedence: code default → appsettings.json (this line) → any later Configure<T> action.