Show role descriptions in both languages on the Groups Roles tab
Task #81: The Groups editor's Roles tab previously displayed only the description in the active UI language with the role's machine name as a small subtitle. Bilingual admin teams asked to see both languages at once. Changes (artifacts/tx-os/src/pages/admin.tsx): - Imported Tooltip, TooltipContent, TooltipTrigger from @/components/ui/tooltip (TooltipProvider was already mounted at the App root, so no provider wiring was needed). - Refactored each role row in the Roles tab of GroupDetailEditor: * Primary line: description in the active language (descriptionAr when lang === "ar", otherwise descriptionEn). Falls back to the other-language description, then to the role's name when no descriptions exist. * Secondary line (smaller, muted): the OTHER language's description, rendered with the appropriate dir attribute. Only shown when both descriptions are present so single-description roles fall back cleanly. * Machine name remains visible as a small monospace subtitle on the trailing edge of the row. * The whole row is wrapped in a Tooltip whose content shows both descriptions (each with its proper dir) plus the machine name for full context on hover. - Added data-testid="group-role-<id>-secondary" so the secondary line is easily targetable from tests. Verification: - Type-checked tx-os (only pre-existing errors elsewhere in admin.tsx remain; none introduced by this change). - e2e test passed: logged in as admin, opened a group, switched to the Roles tab, confirmed primary + secondary description lines, hovered to see the bilingual tooltip, toggled the UI language and confirmed the lines swapped, and confirmed checkboxes still toggle through the TooltipTrigger asChild wrapper. The single-description-only fallback could not be exercised against seeded data (all seeded roles are bilingual), but the rendering logic gracefully handles that case via the `heading` and `showSecondary` guards. Also reverts an unrelated stray modification to artifacts/tx-os/public/opengraph.jpg that was swept into the previous auto-commit, restoring it to the version from HEAD~1. Follow-up proposed: #88 "Let admins edit role descriptions in both languages". Replit-Task-Id: dfd3b45c-7b85-4c30-b0f9-3bfbab81be8c
This commit is contained in:
@@ -67,6 +67,7 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { formatDate as formatDateUtil, formatWeekday as formatWeekdayUtil } from "@/lib/i18n-format";
|
||||
@@ -2782,23 +2783,52 @@ function GroupDetailEditor({ groupId, onClose, onSaved }: { groupId: number; onC
|
||||
{tab === "roles" && (
|
||||
<div className="space-y-1 max-h-72 overflow-y-auto">
|
||||
<p className="text-xs text-muted-foreground px-1 pb-2">{t("admin.groups.rolesHint")}</p>
|
||||
{roles?.map((r) => (
|
||||
<label
|
||||
key={r.id}
|
||||
className="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-slate-100 cursor-pointer"
|
||||
data-testid={`group-role-${r.id}`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={roleIds.has(r.id)}
|
||||
onChange={() => toggle(roleIds, r.id, setRoleIds)}
|
||||
/>
|
||||
<span className="text-sm flex-1">
|
||||
{(lang === "ar" ? r.descriptionAr : r.descriptionEn) || r.name}
|
||||
</span>
|
||||
<span className="text-[10px] text-muted-foreground">{r.name}</span>
|
||||
</label>
|
||||
))}
|
||||
{roles?.map((r) => {
|
||||
const primaryDesc = lang === "ar" ? r.descriptionAr : r.descriptionEn;
|
||||
const secondaryDesc = lang === "ar" ? r.descriptionEn : r.descriptionAr;
|
||||
const secondaryDir = lang === "ar" ? "ltr" : "rtl";
|
||||
const heading = primaryDesc || secondaryDesc || r.name;
|
||||
const showSecondary = !!(primaryDesc && secondaryDesc);
|
||||
return (
|
||||
<Tooltip key={r.id}>
|
||||
<TooltipTrigger asChild>
|
||||
<label
|
||||
className="flex items-start gap-2 px-3 py-2 rounded-lg hover:bg-slate-100 cursor-pointer"
|
||||
data-testid={`group-role-${r.id}`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-1"
|
||||
checked={roleIds.has(r.id)}
|
||||
onChange={() => toggle(roleIds, r.id, setRoleIds)}
|
||||
/>
|
||||
<span className="flex-1 min-w-0">
|
||||
<span className="block text-sm">{heading}</span>
|
||||
{showSecondary && (
|
||||
<span
|
||||
className="block text-xs text-muted-foreground"
|
||||
dir={secondaryDir}
|
||||
data-testid={`group-role-${r.id}-secondary`}
|
||||
>
|
||||
{secondaryDesc}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
<span className="text-[10px] text-muted-foreground mt-1 shrink-0 font-mono">
|
||||
{r.name}
|
||||
</span>
|
||||
</label>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" className="max-w-xs">
|
||||
<div className="space-y-1 text-xs">
|
||||
{r.descriptionAr && <div dir="rtl">{r.descriptionAr}</div>}
|
||||
{r.descriptionEn && <div dir="ltr">{r.descriptionEn}</div>}
|
||||
<div className="opacity-70 font-mono" dir="ltr">{r.name}</div>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
{(!roles || roles.length === 0) && (
|
||||
<p className="text-sm text-muted-foreground p-2">{t("admin.groups.rolesEmpty")}</p>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user