diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.ar.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.ar.resx
index a4addbc9..f2aca058 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.ar.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.ar.resx
@@ -6421,7 +6421,7 @@
تستفيد معظم الأقسام من هذه.
- Resgrid Admin Assist
+ Admin Assist
مفعّل
diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.de.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.de.resx
index 569c52cb..c16d2571 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.de.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.de.resx
@@ -6421,7 +6421,7 @@
Die meisten Abteilungen profitieren davon.
- Resgrid Admin Assist
+ Admin Assist
Aktiviert
diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.el.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.el.resx
index f5f7e88b..7486af12 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.el.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.el.resx
@@ -6421,7 +6421,7 @@
Τα περισσότερα τμήματα επωφελούνται από αυτές.
- Resgrid Admin Assist
+ Admin Assist
Ενεργοποιημένο
diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.en.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.en.resx
index 9935880f..48f0e7b2 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.en.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.en.resx
@@ -6421,7 +6421,7 @@
Most departments benefit from these.
- Resgrid Admin Assist
+ Admin Assist
Enabled
diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.es.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.es.resx
index ccab5cda..9c7bb81d 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.es.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.es.resx
@@ -6421,7 +6421,7 @@
La mayoría de los departamentos se benefician de estos.
- Resgrid Admin Assist
+ Admin Assist
Habilitado
diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.fr.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.fr.resx
index b647aed9..1eb709b3 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.fr.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.fr.resx
@@ -6421,7 +6421,7 @@
La plupart des départements en tirent parti.
- Resgrid Admin Assist
+ Admin Assist
Activé
diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.it.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.it.resx
index a3debd46..e52522a1 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.it.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.it.resx
@@ -6421,7 +6421,7 @@
La maggior parte dei dipartimenti ne trae vantaggio.
- Resgrid Admin Assist
+ Admin Assist
Attivato
diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.pl.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.pl.resx
index c3b86fcc..b27959a2 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.pl.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.pl.resx
@@ -6421,7 +6421,7 @@
Większość oddziałów odnosi z nich korzyści.
- Resgrid Admin Assist
+ Admin Assist
Włączone
diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.resx
index 9935880f..48f0e7b2 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.resx
@@ -6421,7 +6421,7 @@
Most departments benefit from these.
- Resgrid Admin Assist
+ Admin Assist
Enabled
diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.sv.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.sv.resx
index 6eba4bfa..98dc54f3 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.sv.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.sv.resx
@@ -6421,7 +6421,7 @@
De flesta avdelningar har nytta av dessa.
- Resgrid Admin Assist
+ Admin Assist
Aktiverad
diff --git a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.uk.resx b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.uk.resx
index fbdf3f94..921b9882 100644
--- a/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.uk.resx
+++ b/Core/Resgrid.Localization/Areas/User/AdminAssist/AdminAssist.uk.resx
@@ -6421,7 +6421,7 @@
Більшість підрозділів отримують користь від цих модулів.
- Resgrid Admin Assist
+ Admin Assist
Увімкнено
diff --git a/Core/Resgrid.Services/AdminAssist/AdminAssistFeatureAvailability.cs b/Core/Resgrid.Services/AdminAssist/AdminAssistFeatureAvailability.cs
index 6144a4d9..c8d60632 100644
--- a/Core/Resgrid.Services/AdminAssist/AdminAssistFeatureAvailability.cs
+++ b/Core/Resgrid.Services/AdminAssist/AdminAssistFeatureAvailability.cs
@@ -9,19 +9,29 @@ namespace Resgrid.Services.AdminAssist
/// Fresh rollout checks. Missing flags and evaluation failures disable the optional feature.
public static class AdminAssistFeatureAvailability
{
- public static async Task IsEnabledAsync(IFeatureToggleService flags, int departmentId, bool setup, CancellationToken ct = default)
+ public static Task IsEnabledAsync(IFeatureToggleService flags, int departmentId, bool setup, CancellationToken ct = default) =>
+ IsFlagEnabledAsync(flags, setup ? FeatureFlagKeys.AdminSetup : FeatureFlagKeys.AdminAssist, departmentId, ct);
+
+ ///
+ /// The Admin Assist workspace (its menu entry and pages) launches with its AI, after the Setup Wizard and Setup Report.
+ /// Admin.Assist alone still drives field help, impact previews and digests; the workspace also needs Ai.AdminAssist.
+ ///
+ public static async Task IsWorkspaceEnabledAsync(IFeatureToggleService flags, int departmentId, CancellationToken ct = default) =>
+ await IsEnabledAsync(flags, departmentId, false, ct) && await IsFlagEnabledAsync(flags, FeatureFlagKeys.AiAdminAssist, departmentId, ct);
+
+ public static async Task CanConfigureOperatingProfileAsync(IFeatureToggleService flags, int departmentId, CancellationToken ct = default) =>
+ await IsEnabledAsync(flags, departmentId, true, ct) || await IsEnabledAsync(flags, departmentId, false, ct);
+
+ private static async Task IsFlagEnabledAsync(IFeatureToggleService flags, string key, int departmentId, CancellationToken ct)
{
ct.ThrowIfCancellationRequested();
if (departmentId <= 0) return false;
try
{
- return (await flags.EvaluateFreshAsync(setup ? FeatureFlagKeys.AdminSetup : FeatureFlagKeys.AdminAssist, departmentId).WaitAsync(ct))?.IsEnabled == true;
+ return (await flags.EvaluateFreshAsync(key, departmentId).WaitAsync(ct))?.IsEnabled == true;
}
catch (OperationCanceledException) when (ct.IsCancellationRequested) { throw; }
catch (Exception) { return false; }
}
-
- public static async Task CanConfigureOperatingProfileAsync(IFeatureToggleService flags, int departmentId, CancellationToken ct = default) =>
- await IsEnabledAsync(flags, departmentId, true, ct) || await IsEnabledAsync(flags, departmentId, false, ct);
}
}
diff --git a/Tests/Resgrid.Tests/AdminAssist/FeatureToggleTests.cs b/Tests/Resgrid.Tests/AdminAssist/FeatureToggleTests.cs
index 6d2ab42c..1564d274 100644
--- a/Tests/Resgrid.Tests/AdminAssist/FeatureToggleTests.cs
+++ b/Tests/Resgrid.Tests/AdminAssist/FeatureToggleTests.cs
@@ -42,6 +42,22 @@ public async Task Setup_and_assist_are_independent_and_AI_does_not_enable_either
Assert.That(await AdminAssistFeatureAvailability.CanConfigureOperatingProfileAsync(_flags.Object,7), Is.EqualTo(setup || assist));
_flags.Verify(f => f.EvaluateFreshAsync(FeatureFlagKeys.AiAdminAssist,7), Times.Never);
}
+ [TestCase(false,false)] [TestCase(true,false)] [TestCase(false,true)] [TestCase(true,true)]
+ public async Task Workspace_launches_only_with_both_assist_and_AI(bool assist, bool ai)
+ {
+ Set(FeatureFlagKeys.AdminAssist,assist); Set(FeatureFlagKeys.AiAdminAssist,ai);
+ Assert.That(await AdminAssistFeatureAvailability.IsWorkspaceEnabledAsync(_flags.Object,7), Is.EqualTo(assist && ai));
+ // Field help, previews and digests keep following Admin.Assist alone.
+ Assert.That(await _access.CanAccessAsync(Actor,false), Is.EqualTo(assist));
+ }
+ [Test]
+ public async Task Workspace_fails_closed_when_the_AI_flag_is_missing_or_unavailable()
+ {
+ Set(FeatureFlagKeys.AdminAssist,true);
+ Assert.That(await AdminAssistFeatureAvailability.IsWorkspaceEnabledAsync(_flags.Object,7), Is.False);
+ _flags.Setup(f => f.EvaluateFreshAsync(FeatureFlagKeys.AiAdminAssist,7)).ThrowsAsync(new InvalidOperationException("Store unavailable"));
+ Assert.That(await AdminAssistFeatureAvailability.IsWorkspaceEnabledAsync(_flags.Object,7), Is.False);
+ }
[TestCase(true)] [TestCase(false)]
public async Task Missing_flag_and_store_outage_fail_closed(bool setup)
{
diff --git a/Tests/Resgrid.Tests/AdminAssist/SetupPromptVisibilityTests.cs b/Tests/Resgrid.Tests/AdminAssist/SetupPromptVisibilityTests.cs
new file mode 100644
index 00000000..261bbcb0
--- /dev/null
+++ b/Tests/Resgrid.Tests/AdminAssist/SetupPromptVisibilityTests.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Security.Claims;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Mvc.ViewComponents;
+using Microsoft.AspNetCore.Mvc.ViewEngines;
+using Moq;
+using NUnit.Framework;
+using Resgrid.AdminAssist;
+using Resgrid.Model.AdminAssist;
+using Resgrid.Providers.Claims;
+using Resgrid.Web.Helpers;
+using Resgrid.Web.ViewComponents;
+
+namespace Resgrid.Tests.AdminAssist
+{
+ /// The dashboard's Setup Wizard banner is for department administrators only.
+ [TestFixture, NonParallelizable]
+ public class SetupPromptVisibilityTests
+ {
+ private static readonly AdminAssistActor Actor = new(7, "user-1");
+ private static readonly ConfigurationCatalog Catalog = new();
+ private IHttpContextAccessor _previousAccessor;
+ private Mock _access;
+ private Mock _repository;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _previousAccessor = ClaimsAuthorizationHelper._httpContextAccessor;
+ _access = new Mock(MockBehavior.Strict);
+ _repository = new Mock(MockBehavior.Strict);
+ }
+
+ [TearDown]
+ public void TearDown() => ClaimsAuthorizationHelper._httpContextAccessor = _previousAccessor;
+
+ [Test]
+ public async Task Member_never_sees_the_banner_and_costs_no_flag_or_workspace_read()
+ {
+ var result = await InvokeAsync(admin: false);
+
+ Assert.That(result, Is.InstanceOf());
+ Assert.That(((ContentViewComponentResult)result).Content, Is.Empty);
+ _access.VerifyNoOtherCalls(); _repository.VerifyNoOtherCalls();
+ }
+
+ [Test]
+ public async Task Admin_sees_the_banner_while_setup_is_open()
+ {
+ _access.Setup(a => a.CanAccessAsync(It.Is(x => x.DepartmentId == Actor.DepartmentId && x.UserId == Actor.UserId), true, It.IsAny())).ReturnsAsync(true);
+ _repository.Setup(r => r.GetWorkspaceAsync(Actor.DepartmentId, Actor.UserId, Catalog.Version, It.IsAny()))
+ .ReturnsAsync(new SetupWorkspace(Actor.DepartmentId, 0, SetupMode.Fresh, new Dictionary(), Array.Empty(), Array.Empty(), Catalog.Version, null));
+
+ var result = await InvokeAsync(admin: true);
+
+ Assert.That(result, Is.InstanceOf());
+ }
+
+ [Test]
+ public async Task Admin_claim_alone_is_not_enough_when_fresh_access_is_refused()
+ {
+ // The claim may be stale; the fresh membership and rollout check still decides.
+ _access.Setup(a => a.CanAccessAsync(It.IsAny(), true, It.IsAny())).ReturnsAsync(false);
+
+ var result = await InvokeAsync(admin: true);
+
+ Assert.That(((ContentViewComponentResult)result).Content, Is.Empty);
+ _repository.VerifyNoOtherCalls();
+ }
+
+ private async Task InvokeAsync(bool admin)
+ {
+ var claims = new List { new(ClaimTypes.PrimarySid, Actor.UserId), new(ClaimTypes.PrimaryGroupSid, Actor.DepartmentId.ToString()) };
+ if (admin) claims.Add(new Claim(ResgridClaimTypes.Resources.Department, ResgridClaimTypes.Actions.Update));
+ var http = new DefaultHttpContext { User = new ClaimsPrincipal(new ClaimsIdentity(claims, "Test")) };
+ ClaimsAuthorizationHelper._httpContextAccessor = new HttpContextAccessor { HttpContext = http };
+
+ var component = new AdminAssistSetupPromptViewComponent(_access.Object, _repository.Object, Catalog)
+ {
+ ViewComponentContext = new ViewComponentContext { ViewContext = new ViewContext { HttpContext = http } },
+ ViewEngine = Mock.Of()
+ };
+ return await component.InvokeAsync();
+ }
+ }
+}
diff --git a/Tests/Resgrid.Tests/Web/ApiLocalizationRegistrationTests.cs b/Tests/Resgrid.Tests/Web/ApiLocalizationRegistrationTests.cs
new file mode 100644
index 00000000..6c48aa99
--- /dev/null
+++ b/Tests/Resgrid.Tests/Web/ApiLocalizationRegistrationTests.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using FluentAssertions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Localization;
+using NUnit.Framework;
+using AdminAssistLabels = Resgrid.Localization.Areas.User.AdminAssist.AdminAssist;
+
+namespace Resgrid.Tests.Web
+{
+ ///
+ /// The API host never registered localization, so every v4 controller taking an IStringLocalizer (Admin Assist among
+ /// them) failed to construct and returned 500. The Setup Wizard and Setup Report showed only "The report could not be
+ /// loaded" because their Catalog and Overview reads never reached the controller.
+ ///
+ [TestFixture]
+ public class ApiLocalizationRegistrationTests
+ {
+ [Test]
+ public void Api_startup_registers_localization_for_controllers_that_take_string_localizers()
+ {
+ var localized = typeof(Resgrid.Web.Services.Controllers.v4.AdminAssistController).Assembly.GetTypes()
+ .Where(t => typeof(ControllerBase).IsAssignableFrom(t) && !t.IsAbstract)
+ .Where(t => t.GetConstructors().Any(c => c.GetParameters().Any(p => p.ParameterType.IsGenericType &&
+ p.ParameterType.GetGenericTypeDefinition() == typeof(IStringLocalizer<>))))
+ .Select(t => t.Name)
+ .ToList();
+ localized.Should().Contain("AdminAssistController");
+
+ var startup = File.ReadAllText(FindRepositoryFile("Web/Resgrid.Web.Services/Startup.cs"));
+ Regex.IsMatch(startup, @"^\s*services\.AddLocalization\(", RegexOptions.Multiline)
+ .Should().BeTrue($"the API constructs {string.Join(", ", localized)} with an IStringLocalizer");
+ }
+
+ [TestCase("")]
+ [TestCase("en")]
+ [TestCase("de")]
+ public void Admin_assist_catalog_strings_resolve_from_the_registered_localizer(string culture)
+ {
+ var previous = CultureInfo.CurrentUICulture;
+ try
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
+ // The host supplies logging; the localizer factory depends on it.
+ using var provider = new ServiceCollection().AddLogging().AddLocalization().BuildServiceProvider();
+ var labels = provider.GetRequiredService>();
+
+ // The same projection the Catalog endpoint returns to the page.
+ var strings = labels.GetAllStrings(true).GroupBy(s => s.Name).ToDictionary(g => g.Key, g => g.First().Value);
+
+ strings.Should().ContainKey("Ui.Error");
+ strings["Ui.Title"].Should().Be("Admin Assist");
+ }
+ finally { CultureInfo.CurrentUICulture = previous; }
+ }
+
+ private static string FindRepositoryFile(string relativePath)
+ {
+ var directory = new DirectoryInfo(TestContext.CurrentContext.TestDirectory);
+
+ while (directory != null && !File.Exists(Path.Combine(directory.FullName, "Resgrid.sln")))
+ directory = directory.Parent;
+
+ if (directory == null)
+ throw new InvalidOperationException("Unable to locate the repository root.");
+
+ return Path.Combine(directory.FullName, relativePath.Replace('/', Path.DirectorySeparatorChar));
+ }
+ }
+}
diff --git a/Web/Resgrid.Web.Services/Startup.cs b/Web/Resgrid.Web.Services/Startup.cs
index 756e4440..0d3b27ca 100644
--- a/Web/Resgrid.Web.Services/Startup.cs
+++ b/Web/Resgrid.Web.Services/Startup.cs
@@ -166,6 +166,10 @@ public void ConfigureServices(IServiceCollection services)
services.AddCors();
+ // v4 controllers (Admin Assist, Checklists, Inventory, Work Orders) take IStringLocalizer. Without this
+ // registration none of them can be constructed and every request to them fails with a 500.
+ services.AddLocalization();
+
services.AddControllers(options =>
{
// ADP department operation lock: refuses department-scoped mutations with 423 Locked
diff --git a/Web/Resgrid.Web/Areas/User/Controllers/AdminAssistController.cs b/Web/Resgrid.Web/Areas/User/Controllers/AdminAssistController.cs
index bf80556e..011efda5 100644
--- a/Web/Resgrid.Web/Areas/User/Controllers/AdminAssistController.cs
+++ b/Web/Resgrid.Web/Areas/User/Controllers/AdminAssistController.cs
@@ -12,7 +12,7 @@ namespace Resgrid.Web.Areas.User.Controllers
[Authorize]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
public sealed class AdminAssistController(IAdminAssistAccessService access, IAdminAssistService service,
- IDepartmentDataProtectionService protection) : SecureBaseController
+ IDepartmentDataProtectionService protection, IFeatureToggleService flags) : SecureBaseController
{
[HttpGet]
public Task Index(CancellationToken cancellationToken) => PageAsync("overview", false, cancellationToken);
@@ -48,6 +48,7 @@ public async Task PrintReport(bool setup, CancellationToken cance
Response.Headers["Referrer-Policy"] = "no-referrer";
try
{
+ if (!setup && !await Resgrid.Services.AdminAssist.AdminAssistFeatureAvailability.IsWorkspaceEnabledAsync(flags, DepartmentId, cancellationToken)) return NotFound();
// A new authorized read: no previously rendered worklist content or browser snapshot is reused.
var overview = await service.GetOverviewAsync(new AdminAssistActor(DepartmentId, UserId, CultureInfo.CurrentUICulture.Name), setup, cancellationToken);
return View("PrintReport", overview);
@@ -75,6 +76,8 @@ private async Task PageAsync(string page, bool setup, Cancellatio
{
var actor = new AdminAssistActor(DepartmentId, UserId, CultureInfo.CurrentUICulture.Name);
if (!await access.CanAccessAsync(actor, setup, ct)) return NotFound();
+ // The workspace launches after the Setup Wizard and Setup Report; it stays hidden until its AI is on.
+ if (!setup && !await Resgrid.Services.AdminAssist.AdminAssistFeatureAvailability.IsWorkspaceEnabledAsync(flags, DepartmentId, ct)) return NotFound();
ViewBag.AdminAssistPage = page;
ViewBag.AdminAssistSetup = setup;
ViewBag.AdminAssistProtected = await protection.IsProtectionEnforcedAsync(DepartmentId).WaitAsync(ct);
diff --git a/Web/Resgrid.Web/Areas/User/Views/Shared/_TopNavbar.cshtml b/Web/Resgrid.Web/Areas/User/Views/Shared/_TopNavbar.cshtml
index ba036073..c778aa62 100644
--- a/Web/Resgrid.Web/Areas/User/Views/Shared/_TopNavbar.cshtml
+++ b/Web/Resgrid.Web/Areas/User/Views/Shared/_TopNavbar.cshtml
@@ -4,8 +4,9 @@
@{
var adminSetupVisible = ClaimsAuthorizationHelper.IsUserDepartmentAdmin() &&
await Resgrid.Services.AdminAssist.AdminAssistFeatureAvailability.IsEnabledAsync(featureToggleService, ClaimsAuthorizationHelper.GetDepartmentId(), true, Context.RequestAborted);
+ // The workspace launches after Setup Wizard and Setup Report: it also needs Ai.AdminAssist, not just Admin.Assist.
var adminAssistVisible = ClaimsAuthorizationHelper.IsUserDepartmentAdmin() &&
- await Resgrid.Services.AdminAssist.AdminAssistFeatureAvailability.IsEnabledAsync(featureToggleService, ClaimsAuthorizationHelper.GetDepartmentId(), false, Context.RequestAborted);
+ await Resgrid.Services.AdminAssist.AdminAssistFeatureAvailability.IsWorkspaceEnabledAsync(featureToggleService, ClaimsAuthorizationHelper.GetDepartmentId(), Context.RequestAborted);
// Chat.System gates the moderation console link; it is only useful to department or group admins.
var chatModerationVisible = ClaimsAuthorizationHelper.IsUserDepartmentOrGroupAdmin(0) &&
await featureToggleService.IsEnabledAsync(FeatureFlagKeys.ChatSystem, ClaimsAuthorizationHelper.GetDepartmentId());
@@ -21,11 +22,11 @@