@iblai/iblai-js 1.17.22 → 1.17.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -88768,7 +88768,7 @@ function UsersTab({ tenant, onInviteClick }) {
88768
88768
  });
88769
88769
  useEffect(() => {
88770
88770
  const handler = setTimeout(() => {
88771
- if (searchQuery.length > 3) {
88771
+ if (searchQuery.length > 2) {
88772
88772
  setDebouncedSearchQuery(searchQuery);
88773
88773
  }
88774
88774
  else {
@@ -89157,7 +89157,7 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
89157
89157
  platformKey: tenant,
89158
89158
  page,
89159
89159
  pageSize: 10,
89160
- ...(debouncedSearchQuery.length > 3 && { name: debouncedSearchQuery }),
89160
+ ...(debouncedSearchQuery.length > 2 && { name: debouncedSearchQuery }),
89161
89161
  }, { skip: isTeam });
89162
89162
  const { data: platformGroupsData, isLoading: isLoadingPlatformGroups, isError: isErrorPlatformGroups, refetch: refetchPlatformGroups, } = usePlatformUserGroupsQuery({
89163
89163
  platformKey: tenant,
@@ -89165,12 +89165,12 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
89165
89165
  withPermissions: true,
89166
89166
  page,
89167
89167
  pageSize: 10,
89168
- ...(debouncedSearchQuery.length > 3 && { name: debouncedSearchQuery }),
89168
+ ...(debouncedSearchQuery.length > 2 && { name: debouncedSearchQuery }),
89169
89169
  }, { skip: !isTeam });
89170
89170
  // Debounce search query
89171
89171
  useEffect(() => {
89172
89172
  const handler = setTimeout(() => {
89173
- if (searchQuery.length > 3) {
89173
+ if (searchQuery.length > 2) {
89174
89174
  setDebouncedSearchQuery(searchQuery);
89175
89175
  setPage(1); // Reset to first page on new search
89176
89176
  }
@@ -89448,8 +89448,7 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
89448
89448
  }
89449
89449
  toast.success(isTeam ? 'Team created' : 'Group created');
89450
89450
  }
89451
- setIsOpen(false);
89452
- setEditing(null);
89451
+ closeDialog();
89453
89452
  }
89454
89453
  catch (e) {
89455
89454
  const errorMessage = ((_a = e === null || e === void 0 ? void 0 : e.data) === null || _a === void 0 ? void 0 : _a.detail) || (e === null || e === void 0 ? void 0 : e.message);
@@ -89489,6 +89488,16 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
89489
89488
  setDeletingGroupId(null);
89490
89489
  }
89491
89490
  }
89491
+ // Reset edit state when the dialog closes so re-opening the same group/team
89492
+ // re-triggers the details query and the members-population effect.
89493
+ function closeDialog() {
89494
+ setIsOpen(false);
89495
+ setEditing(null);
89496
+ setEditingGroupId(null);
89497
+ setEditingTeamId(null);
89498
+ setMembers([]);
89499
+ setOriginalMembers([]);
89500
+ }
89492
89501
  function openSharePanel(g) {
89493
89502
  setShareTeamId(g.id);
89494
89503
  setShareTeamName(g.name);
@@ -89496,7 +89505,14 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
89496
89505
  }
89497
89506
  return (jsxs("div", { className: "mt-4", children: [jsxs("div", { className: `flex mb-6 gap-2 ${isTeam ? 'flex-col sm:flex-row sm:items-center sm:justify-between' : 'flex-row items-center justify-between'}`, children: [jsxs("div", { className: "relative max-w-sm w-full sm:w-auto", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: isTeam ? 'Search teams' : 'Search groups', "aria-label": isTeam ? 'Search teams' : 'Search groups', className: "pl-10 pr-10 focus:ring-blue-500 focus:border-blue-500 h-[35px]" }), isLoading && (jsx(LoaderCircle, { "data-testid": "search-spinner", className: "absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400 animate-spin", "aria-hidden": "true" }))] }), jsxs("div", { className: "flex gap-2", children: [isTeam && hasInviteUserPermission && onInviteClick && (jsx(Button$1, { onClick: onInviteClick, "aria-label": "Invite users", className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", children: "Invite" })), isTeam ? (hasCreateTeamPermission && (jsx(Button$1, { onClick: openNew, "aria-label": "New team", className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", children: "New Team" }))) : (jsx(Button$1, { onClick: openNew, "aria-label": "New group", className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", children: "New Group" }))] })] }), isLoading && (jsx("div", { className: "flex justify-center items-center h-64", children: jsx("div", { className: "py-8 text-center text-sm text-gray-500 dark:text-gray-400", children: "Loading\u2026" }) })), isError && (jsx("div", { className: "py-8 text-center text-sm text-red-500", children: isTeam ? 'Failed to load teams' : 'Failed to load groups' })), !isLoading && !isError && (jsx("div", { className: "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-x-auto", children: jsxs("table", { className: "w-full text-sm", children: [jsx("thead", { className: "bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600", children: jsxs("tr", { children: [jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400", children: isTeam ? 'Team Name' : 'Group Name' }), !isTeam && (jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400", children: "Unique ID" })), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400", children: "Description" }), jsx("th", { className: "px-6 py-3 text-right font-medium text-gray-500 dark:text-gray-400 w-[120px]" })] }) }), jsxs("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: [groups.map((g) => (jsxs("tr", { children: [jsx("td", { className: "px-6 py-4 text-gray-900 dark:text-gray-100 text-sm", children: g.name }), !isTeam && (jsx("td", { className: "px-6 py-4 text-gray-600 dark:text-gray-300 text-sm", children: g.unique_id })), jsx("td", { className: "px-6 py-4 text-gray-600 dark:text-gray-300 text-sm", children: g.description }), jsx("td", { className: "px-6 py-4", children: jsxs("div", { className: "flex gap-2 justify-end", children: [isTeam && (jsx(WithPermissions, { rbacResource: `/platforms/${tenant}/usergroups/${g.id}/#share_usergroup`, rbacPermissions: rbacPermissions, children: ({ hasPermission }) => (hasPermission || !enableRbac) && (jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => openSharePanel(g), disabled: deletingGroupId === g.id, "aria-label": `Share team ${g.name}`, children: jsx(Share2, { className: "h-4 w-4", "aria-hidden": "true" }) })) })), jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => openEdit(g), disabled: deletingGroupId === g.id, "aria-label": `Edit ${isTeam ? 'team' : 'group'} ${g.name}`, children: jsx(Pencil, { className: "h-4 w-4", "aria-hidden": "true" }) }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, children: jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => onDelete(g), className: "text-red-600 hover:text-red-700", disabled: deletingGroupId === g.id ||
89498
89507
  g.is_internal ||
89499
- !g.permissions.object.delete, "aria-label": `Delete ${isTeam ? 'team' : 'group'} ${g.name}`, children: deletingGroupId === g.id ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" })) : (jsx(Trash2, { className: "h-4 w-4", "aria-hidden": "true" })) }) }) }), g.is_internal && (jsx(TooltipContent, { children: jsxs("p", { children: ["Cannot delete internal ", isTeam ? 'teams' : 'groups'] }) })), !g.permissions.object.delete && (jsx(TooltipContent, { children: jsxs("p", { children: ["Cannot delete ", isTeam ? 'teams' : 'groups'] }) }))] }) })] }) })] }, g.id))), groups.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: isTeam ? 3 : 4, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: isTeam ? 'No teams found' : 'No groups found' }) }))] })] }) })), !isLoading && !isError && (jsx(AdvancedPagination, { variant: "footer", className: "-mx-6 -mb-6 mt-4 rounded-b-lg", totalPages: totalPages, currentPage: page, onPageChange: (newPage) => handlePageChange(newPage), totalCount: data === null || data === void 0 ? void 0 : data.count, itemsPerPage: 10, itemLabel: "groups" })), jsx(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: jsxs(DialogContent, { "aria-describedby": undefined, className: "max-w-2xl max-h-[90vh] overflow-y-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: editing ? (isTeam ? 'Edit Team' : 'Edit Group') : isTeam ? 'New Team' : 'New Group' }) }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$2, { htmlFor: "g-name", children: isTeam ? 'Team Name' : 'Group Name' }), jsx(Input, { id: "g-name", value: form.name, onChange: (e) => setForm({ ...form, name: e.target.value }), placeholder: isTeam ? 'Enter team name' : 'Enter group name', required: true })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$2, { htmlFor: "g-desc", children: "Description" }), jsx(Input, { id: "g-desc", value: form.description, onChange: (e) => setForm({ ...form, description: e.target.value }), placeholder: isTeam ? 'Enter team description' : 'Enter group description' })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$2, { children: isTeam ? 'Team Members' : 'Group Members' }), jsx("div", { className: "space-y-2", children: members.length > 0 ? (jsx("div", { className: "space-y-2 max-h-48 overflow-y-auto border border-gray-200 dark:border-gray-700 rounded-md p-2", children: members.map((member) => (jsxs("div", { className: "flex items-center justify-between bg-gray-50 dark:bg-gray-800 p-2 rounded-md", children: [jsxs("div", { className: "flex flex-col", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: member.name || member.username }), member.email && (jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: member.email }))] }), jsx(Button$1, { type: "button", variant: "ghost", size: "sm", onClick: () => removeMember(member.id), className: "h-8 w-8 p-0 text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-900/20", "aria-label": `Remove ${member.name}`, children: jsx(X$1, { className: "h-4 w-4" }) })] }, member.id))) })) : (jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400 p-4 text-center border border-dashed border-gray-300 dark:border-gray-600 rounded-md", children: "No members added yet" })) })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$2, { htmlFor: "user-search", children: "Add Members" }), jsxs("div", { className: "relative", children: [jsx(Input, { id: "user-search", value: userSearch, onChange: (e) => {
89508
+ !g.permissions.object.delete, "aria-label": `Delete ${isTeam ? 'team' : 'group'} ${g.name}`, children: deletingGroupId === g.id ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" })) : (jsx(Trash2, { className: "h-4 w-4", "aria-hidden": "true" })) }) }) }), g.is_internal && (jsx(TooltipContent, { children: jsxs("p", { children: ["Cannot delete internal ", isTeam ? 'teams' : 'groups'] }) })), !g.permissions.object.delete && (jsx(TooltipContent, { children: jsxs("p", { children: ["Cannot delete ", isTeam ? 'teams' : 'groups'] }) }))] }) })] }) })] }, g.id))), groups.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: isTeam ? 3 : 4, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: isTeam ? 'No teams found' : 'No groups found' }) }))] })] }) })), !isLoading && !isError && (jsx(AdvancedPagination, { variant: "footer", className: "-mx-6 -mb-6 mt-4 rounded-b-lg", totalPages: totalPages, currentPage: page, onPageChange: (newPage) => handlePageChange(newPage), totalCount: data === null || data === void 0 ? void 0 : data.count, itemsPerPage: 10, itemLabel: "groups" })), jsx(Dialog, { open: isOpen, onOpenChange: (open) => {
89509
+ if (open) {
89510
+ setIsOpen(true);
89511
+ }
89512
+ else {
89513
+ closeDialog();
89514
+ }
89515
+ }, children: jsxs(DialogContent, { "aria-describedby": undefined, className: "max-w-2xl max-h-[90vh] overflow-y-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: editing ? (isTeam ? 'Edit Team' : 'Edit Group') : isTeam ? 'New Team' : 'New Group' }) }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$2, { htmlFor: "g-name", children: isTeam ? 'Team Name' : 'Group Name' }), jsx(Input, { id: "g-name", value: form.name, onChange: (e) => setForm({ ...form, name: e.target.value }), placeholder: isTeam ? 'Enter team name' : 'Enter group name', required: true })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$2, { htmlFor: "g-desc", children: "Description" }), jsx(Input, { id: "g-desc", value: form.description, onChange: (e) => setForm({ ...form, description: e.target.value }), placeholder: isTeam ? 'Enter team description' : 'Enter group description' })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$2, { children: isTeam ? 'Team Members' : 'Group Members' }), jsx("div", { className: "space-y-2", children: members.length > 0 ? (jsx("div", { className: "space-y-2 max-h-48 overflow-y-auto border border-gray-200 dark:border-gray-700 rounded-md p-2", children: members.map((member) => (jsxs("div", { className: "flex items-center justify-between bg-gray-50 dark:bg-gray-800 p-2 rounded-md", children: [jsxs("div", { className: "flex flex-col", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: member.name || member.username }), member.email && (jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: member.email }))] }), jsx(Button$1, { type: "button", variant: "ghost", size: "sm", onClick: () => removeMember(member.id), className: "h-8 w-8 p-0 text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-900/20", "aria-label": `Remove ${member.name}`, children: jsx(X$1, { className: "h-4 w-4" }) })] }, member.id))) })) : (jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400 p-4 text-center border border-dashed border-gray-300 dark:border-gray-600 rounded-md", children: "No members added yet" })) })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$2, { htmlFor: "user-search", children: "Add Members" }), jsxs("div", { className: "relative", children: [jsx(Input, { id: "user-search", value: userSearch, onChange: (e) => {
89500
89516
  setUserSearch(e.target.value);
89501
89517
  setShowUserSearch(e.target.value.length > 0);
89502
89518
  }, onFocus: () => setShowUserSearch(userSearch.length > 0), placeholder: "Type to search users...", className: "w-full" }), showUserSearch && availableUsers.length > 0 && (jsx("div", { className: "absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg max-h-48 overflow-y-auto z-50", children: availableUsers.map((user) => (jsxs("button", { type: "button", onClick: () => {
@@ -89507,7 +89523,7 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
89507
89523
  email: user.email,
89508
89524
  username: user.username,
89509
89525
  });
89510
- }, className: "w-full text-left px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 flex flex-col", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: user.name }), jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: user.email })] }, user.user_id))) })), showUserSearch && userSearch.length > 2 && availableUsers.length === 0 && (jsx("div", { className: "absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg p-3 z-50", children: jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: "No users found" }) }))] }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Type at least 3 characters to search for users" })] })] }), formError && (jsx("div", { className: "mt-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-md", children: jsx("p", { className: "text-sm text-red-600 dark:text-red-400", children: formError }) })), jsxs(DialogFooter, { className: "mt-6", children: [jsx(Button$1, { variant: "outline", onClick: () => setIsOpen(false), children: "Cancel" }), (!isTeam || !editing || (isTeam && hasEditTeamPermission)) && (jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, children: jsxs(Button$1, { onClick: onSubmit, disabled: isSubmitting || (!!editing && (entityDetails === null || entityDetails === void 0 ? void 0 : entityDetails.is_internal)), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white", children: [isSubmitting ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin mr-2", "aria-hidden": "true" })) : null, editing
89526
+ }, className: "w-full text-left px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 flex flex-col", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: user.name }), jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: user.email })] }, user.user_id))) })), showUserSearch && userSearch.length > 2 && availableUsers.length === 0 && (jsx("div", { className: "absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg p-3 z-50", children: jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: "No users found" }) }))] }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Type at least 3 characters to search for users" })] })] }), formError && (jsx("div", { className: "mt-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-md", children: jsx("p", { className: "text-sm text-red-600 dark:text-red-400", children: formError }) })), jsxs(DialogFooter, { className: "mt-6", children: [jsx(Button$1, { variant: "outline", onClick: closeDialog, children: "Cancel" }), (!isTeam || !editing || (isTeam && hasEditTeamPermission)) && (jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, children: jsxs(Button$1, { onClick: onSubmit, disabled: isSubmitting || (!!editing && (entityDetails === null || entityDetails === void 0 ? void 0 : entityDetails.is_internal)), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white", children: [isSubmitting ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin mr-2", "aria-hidden": "true" })) : null, editing
89511
89527
  ? isTeam
89512
89528
  ? 'Save Team'
89513
89529
  : 'Save Group'
@@ -89528,7 +89544,7 @@ function RolesTab({ tenant }) {
89528
89544
  platformKey: tenant,
89529
89545
  page,
89530
89546
  pageSize: 10,
89531
- ...(debouncedSearchQuery.length > 3 && { name: debouncedSearchQuery }),
89547
+ ...(debouncedSearchQuery.length > 2 && { name: debouncedSearchQuery }),
89532
89548
  });
89533
89549
  const [createRole] = useCreateRbacRoleMutation();
89534
89550
  const [updateRole] = useUpdateRbacRoleMutation();
@@ -89536,7 +89552,7 @@ function RolesTab({ tenant }) {
89536
89552
  // Debounce search query
89537
89553
  useEffect(() => {
89538
89554
  const handler = setTimeout(() => {
89539
- if (searchQuery.length > 3) {
89555
+ if (searchQuery.length > 2) {
89540
89556
  setDebouncedSearchQuery(searchQuery);
89541
89557
  setPage(1); // Reset to first page on new search
89542
89558
  }
@@ -89678,7 +89694,7 @@ function PoliciesTab({ tenant }) {
89678
89694
  platformKey: tenant,
89679
89695
  page,
89680
89696
  pageSize: 10,
89681
- ...(debouncedSearchQuery.length > 3 && { name: debouncedSearchQuery }),
89697
+ ...(debouncedSearchQuery.length > 2 && { name: debouncedSearchQuery }),
89682
89698
  });
89683
89699
  const [createPolicy] = useCreateRbacPolicyMutation();
89684
89700
  const [updatePolicy] = useUpdateRbacPolicyMutation();
@@ -89686,7 +89702,7 @@ function PoliciesTab({ tenant }) {
89686
89702
  // Debounce search query
89687
89703
  useEffect(() => {
89688
89704
  const handler = setTimeout(() => {
89689
- if (searchQuery.length > 3) {
89705
+ if (searchQuery.length > 2) {
89690
89706
  setDebouncedSearchQuery(searchQuery);
89691
89707
  setPage(1); // Reset to first page on new search
89692
89708
  }
@@ -89713,6 +89729,7 @@ function PoliciesTab({ tenant }) {
89713
89729
  const [selectedGroups, setSelectedGroups] = useState([]);
89714
89730
  const [originalGroups, setOriginalGroups] = useState([]);
89715
89731
  const [roleSearch, setRoleSearch] = useState('');
89732
+ const [debouncedRoleSearch, setDebouncedRoleSearch] = useState('');
89716
89733
  const [userSearch, setUserSearch] = useState('');
89717
89734
  const [groupSearch, setGroupSearch] = useState('');
89718
89735
  const [showRoleSearch, setShowRoleSearch] = useState(false);
@@ -89721,8 +89738,18 @@ function PoliciesTab({ tenant }) {
89721
89738
  const [deletingPolicyId, setDeletingPolicyId] = useState(null);
89722
89739
  // Fetch policy details when editing
89723
89740
  const { data: policyDetails } = useGetRbacPolicyDetailsQuery({ id: editingPolicyId, platform_key: tenant }, { skip: !editingPolicyId });
89724
- // Fetch roles for autocomplete
89725
- const { data: rolesData } = useGetRbacRolesQuery({ platformKey: tenant });
89741
+ // Debounce role search and query the roles endpoint with the search term
89742
+ useEffect(() => {
89743
+ const handler = setTimeout(() => {
89744
+ setDebouncedRoleSearch(roleSearch.trim());
89745
+ }, 300);
89746
+ return () => clearTimeout(handler);
89747
+ }, [roleSearch]);
89748
+ // Fetch roles for autocomplete (server-side filtered by name)
89749
+ const { data: rolesData } = useGetRbacRolesQuery({
89750
+ platformKey: tenant,
89751
+ ...(debouncedRoleSearch.length > 0 && { name: debouncedRoleSearch }),
89752
+ });
89726
89753
  // Fetch groups for autocomplete
89727
89754
  const { data: groupsData } = useGetRbacGroupsQuery({ platformKey: tenant });
89728
89755
  // Fetch users for search
@@ -89744,14 +89771,11 @@ function PoliciesTab({ tenant }) {
89744
89771
  }, [data]);
89745
89772
  // Calculate total pages
89746
89773
  const totalPages = data ? Math.ceil(data.count / 10) : 0;
89747
- // Filter available roles
89774
+ // Roles list (filtering happens server-side via the name query param)
89748
89775
  const availableRoles = useMemo(() => {
89749
89776
  var _a, _b, _c;
89750
- const rolesList = (_c = (_b = (_a = rolesData === null || rolesData === void 0 ? void 0 : rolesData.results) !== null && _a !== void 0 ? _a : rolesData === null || rolesData === void 0 ? void 0 : rolesData.data) !== null && _b !== void 0 ? _b : rolesData) !== null && _c !== void 0 ? _c : [];
89751
- if (!roleSearch)
89752
- return rolesList;
89753
- return rolesList.filter((role) => role.name.toLowerCase().includes(roleSearch.toLowerCase()));
89754
- }, [rolesData, roleSearch]);
89777
+ return (_c = (_b = (_a = rolesData === null || rolesData === void 0 ? void 0 : rolesData.results) !== null && _a !== void 0 ? _a : rolesData === null || rolesData === void 0 ? void 0 : rolesData.data) !== null && _b !== void 0 ? _b : rolesData) !== null && _c !== void 0 ? _c : [];
89778
+ }, [rolesData]);
89755
89779
  // Filter available groups
89756
89780
  const availableGroups = useMemo(() => {
89757
89781
  var _a, _b, _c;
@@ -89992,7 +90016,7 @@ function AlertsTab$1({ tenant }) {
89992
90016
  const [debouncedSearchQuery, setDebouncedSearchQuery] = useState('');
89993
90017
  useEffect(() => {
89994
90018
  const handler = setTimeout(() => {
89995
- if (searchQuery.length > 3) {
90019
+ if (searchQuery.length > 2) {
89996
90020
  setDebouncedSearchQuery(searchQuery);
89997
90021
  setPage(1);
89998
90022
  }
@@ -125995,7 +125995,7 @@ function UsersTab({ tenant, onInviteClick }) {
125995
125995
  });
125996
125996
  useEffect(() => {
125997
125997
  const handler = setTimeout(() => {
125998
- if (searchQuery.length > 3) {
125998
+ if (searchQuery.length > 2) {
125999
125999
  setDebouncedSearchQuery(searchQuery);
126000
126000
  }
126001
126001
  else {
@@ -126384,7 +126384,7 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
126384
126384
  platformKey: tenant,
126385
126385
  page,
126386
126386
  pageSize: 10,
126387
- ...(debouncedSearchQuery.length > 3 && { name: debouncedSearchQuery }),
126387
+ ...(debouncedSearchQuery.length > 2 && { name: debouncedSearchQuery }),
126388
126388
  }, { skip: isTeam });
126389
126389
  const { data: platformGroupsData, isLoading: isLoadingPlatformGroups, isError: isErrorPlatformGroups, refetch: refetchPlatformGroups, } = usePlatformUserGroupsQuery({
126390
126390
  platformKey: tenant,
@@ -126392,12 +126392,12 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
126392
126392
  withPermissions: true,
126393
126393
  page,
126394
126394
  pageSize: 10,
126395
- ...(debouncedSearchQuery.length > 3 && { name: debouncedSearchQuery }),
126395
+ ...(debouncedSearchQuery.length > 2 && { name: debouncedSearchQuery }),
126396
126396
  }, { skip: !isTeam });
126397
126397
  // Debounce search query
126398
126398
  useEffect(() => {
126399
126399
  const handler = setTimeout(() => {
126400
- if (searchQuery.length > 3) {
126400
+ if (searchQuery.length > 2) {
126401
126401
  setDebouncedSearchQuery(searchQuery);
126402
126402
  setPage(1); // Reset to first page on new search
126403
126403
  }
@@ -126675,8 +126675,7 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
126675
126675
  }
126676
126676
  toast.success(isTeam ? 'Team created' : 'Group created');
126677
126677
  }
126678
- setIsOpen(false);
126679
- setEditing(null);
126678
+ closeDialog();
126680
126679
  }
126681
126680
  catch (e) {
126682
126681
  const errorMessage = ((_a = e === null || e === void 0 ? void 0 : e.data) === null || _a === void 0 ? void 0 : _a.detail) || (e === null || e === void 0 ? void 0 : e.message);
@@ -126716,6 +126715,16 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
126716
126715
  setDeletingGroupId(null);
126717
126716
  }
126718
126717
  }
126718
+ // Reset edit state when the dialog closes so re-opening the same group/team
126719
+ // re-triggers the details query and the members-population effect.
126720
+ function closeDialog() {
126721
+ setIsOpen(false);
126722
+ setEditing(null);
126723
+ setEditingGroupId(null);
126724
+ setEditingTeamId(null);
126725
+ setMembers([]);
126726
+ setOriginalMembers([]);
126727
+ }
126719
126728
  function openSharePanel(g) {
126720
126729
  setShareTeamId(g.id);
126721
126730
  setShareTeamName(g.name);
@@ -126723,7 +126732,14 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
126723
126732
  }
126724
126733
  return (jsxs("div", { className: "mt-4", children: [jsxs("div", { className: `flex mb-6 gap-2 ${isTeam ? 'flex-col sm:flex-row sm:items-center sm:justify-between' : 'flex-row items-center justify-between'}`, children: [jsxs("div", { className: "relative max-w-sm w-full sm:w-auto", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: isTeam ? 'Search teams' : 'Search groups', "aria-label": isTeam ? 'Search teams' : 'Search groups', className: "pl-10 pr-10 focus:ring-blue-500 focus:border-blue-500 h-[35px]" }), isLoading && (jsx(LoaderCircle, { "data-testid": "search-spinner", className: "absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400 animate-spin", "aria-hidden": "true" }))] }), jsxs("div", { className: "flex gap-2", children: [isTeam && hasInviteUserPermission && onInviteClick && (jsx(Button$1, { onClick: onInviteClick, "aria-label": "Invite users", className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", children: "Invite" })), isTeam ? (hasCreateTeamPermission && (jsx(Button$1, { onClick: openNew, "aria-label": "New team", className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", children: "New Team" }))) : (jsx(Button$1, { onClick: openNew, "aria-label": "New group", className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", children: "New Group" }))] })] }), isLoading && (jsx("div", { className: "flex justify-center items-center h-64", children: jsx("div", { className: "py-8 text-center text-sm text-gray-500 dark:text-gray-400", children: "Loading\u2026" }) })), isError && (jsx("div", { className: "py-8 text-center text-sm text-red-500", children: isTeam ? 'Failed to load teams' : 'Failed to load groups' })), !isLoading && !isError && (jsx("div", { className: "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-x-auto", children: jsxs("table", { className: "w-full text-sm", children: [jsx("thead", { className: "bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600", children: jsxs("tr", { children: [jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400", children: isTeam ? 'Team Name' : 'Group Name' }), !isTeam && (jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400", children: "Unique ID" })), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400", children: "Description" }), jsx("th", { className: "px-6 py-3 text-right font-medium text-gray-500 dark:text-gray-400 w-[120px]" })] }) }), jsxs("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: [groups.map((g) => (jsxs("tr", { children: [jsx("td", { className: "px-6 py-4 text-gray-900 dark:text-gray-100 text-sm", children: g.name }), !isTeam && (jsx("td", { className: "px-6 py-4 text-gray-600 dark:text-gray-300 text-sm", children: g.unique_id })), jsx("td", { className: "px-6 py-4 text-gray-600 dark:text-gray-300 text-sm", children: g.description }), jsx("td", { className: "px-6 py-4", children: jsxs("div", { className: "flex gap-2 justify-end", children: [isTeam && (jsx(WithPermissions, { rbacResource: `/platforms/${tenant}/usergroups/${g.id}/#share_usergroup`, rbacPermissions: rbacPermissions, children: ({ hasPermission }) => (hasPermission || !enableRbac) && (jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => openSharePanel(g), disabled: deletingGroupId === g.id, "aria-label": `Share team ${g.name}`, children: jsx(Share2, { className: "h-4 w-4", "aria-hidden": "true" }) })) })), jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => openEdit(g), disabled: deletingGroupId === g.id, "aria-label": `Edit ${isTeam ? 'team' : 'group'} ${g.name}`, children: jsx(Pencil, { className: "h-4 w-4", "aria-hidden": "true" }) }), jsx(TooltipProvider, { children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, children: jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => onDelete(g), className: "text-red-600 hover:text-red-700", disabled: deletingGroupId === g.id ||
126725
126734
  g.is_internal ||
126726
- !g.permissions.object.delete, "aria-label": `Delete ${isTeam ? 'team' : 'group'} ${g.name}`, children: deletingGroupId === g.id ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" })) : (jsx(Trash2, { className: "h-4 w-4", "aria-hidden": "true" })) }) }) }), g.is_internal && (jsx(TooltipContent, { children: jsxs("p", { children: ["Cannot delete internal ", isTeam ? 'teams' : 'groups'] }) })), !g.permissions.object.delete && (jsx(TooltipContent, { children: jsxs("p", { children: ["Cannot delete ", isTeam ? 'teams' : 'groups'] }) }))] }) })] }) })] }, g.id))), groups.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: isTeam ? 3 : 4, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: isTeam ? 'No teams found' : 'No groups found' }) }))] })] }) })), !isLoading && !isError && (jsx(AdvancedPagination, { variant: "footer", className: "-mx-6 -mb-6 mt-4 rounded-b-lg", totalPages: totalPages, currentPage: page, onPageChange: (newPage) => handlePageChange(newPage), totalCount: data === null || data === void 0 ? void 0 : data.count, itemsPerPage: 10, itemLabel: "groups" })), jsx(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: jsxs(DialogContent, { "aria-describedby": undefined, className: "max-w-2xl max-h-[90vh] overflow-y-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: editing ? (isTeam ? 'Edit Team' : 'Edit Group') : isTeam ? 'New Team' : 'New Group' }) }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "grid gap-1.5", children: [jsx(Label, { htmlFor: "g-name", children: isTeam ? 'Team Name' : 'Group Name' }), jsx(Input, { id: "g-name", value: form.name, onChange: (e) => setForm({ ...form, name: e.target.value }), placeholder: isTeam ? 'Enter team name' : 'Enter group name', required: true })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label, { htmlFor: "g-desc", children: "Description" }), jsx(Input, { id: "g-desc", value: form.description, onChange: (e) => setForm({ ...form, description: e.target.value }), placeholder: isTeam ? 'Enter team description' : 'Enter group description' })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label, { children: isTeam ? 'Team Members' : 'Group Members' }), jsx("div", { className: "space-y-2", children: members.length > 0 ? (jsx("div", { className: "space-y-2 max-h-48 overflow-y-auto border border-gray-200 dark:border-gray-700 rounded-md p-2", children: members.map((member) => (jsxs("div", { className: "flex items-center justify-between bg-gray-50 dark:bg-gray-800 p-2 rounded-md", children: [jsxs("div", { className: "flex flex-col", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: member.name || member.username }), member.email && (jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: member.email }))] }), jsx(Button$1, { type: "button", variant: "ghost", size: "sm", onClick: () => removeMember(member.id), className: "h-8 w-8 p-0 text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-900/20", "aria-label": `Remove ${member.name}`, children: jsx(X$2, { className: "h-4 w-4" }) })] }, member.id))) })) : (jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400 p-4 text-center border border-dashed border-gray-300 dark:border-gray-600 rounded-md", children: "No members added yet" })) })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label, { htmlFor: "user-search", children: "Add Members" }), jsxs("div", { className: "relative", children: [jsx(Input, { id: "user-search", value: userSearch, onChange: (e) => {
126735
+ !g.permissions.object.delete, "aria-label": `Delete ${isTeam ? 'team' : 'group'} ${g.name}`, children: deletingGroupId === g.id ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" })) : (jsx(Trash2, { className: "h-4 w-4", "aria-hidden": "true" })) }) }) }), g.is_internal && (jsx(TooltipContent, { children: jsxs("p", { children: ["Cannot delete internal ", isTeam ? 'teams' : 'groups'] }) })), !g.permissions.object.delete && (jsx(TooltipContent, { children: jsxs("p", { children: ["Cannot delete ", isTeam ? 'teams' : 'groups'] }) }))] }) })] }) })] }, g.id))), groups.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: isTeam ? 3 : 4, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: isTeam ? 'No teams found' : 'No groups found' }) }))] })] }) })), !isLoading && !isError && (jsx(AdvancedPagination, { variant: "footer", className: "-mx-6 -mb-6 mt-4 rounded-b-lg", totalPages: totalPages, currentPage: page, onPageChange: (newPage) => handlePageChange(newPage), totalCount: data === null || data === void 0 ? void 0 : data.count, itemsPerPage: 10, itemLabel: "groups" })), jsx(Dialog, { open: isOpen, onOpenChange: (open) => {
126736
+ if (open) {
126737
+ setIsOpen(true);
126738
+ }
126739
+ else {
126740
+ closeDialog();
126741
+ }
126742
+ }, children: jsxs(DialogContent, { "aria-describedby": undefined, className: "max-w-2xl max-h-[90vh] overflow-y-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: editing ? (isTeam ? 'Edit Team' : 'Edit Group') : isTeam ? 'New Team' : 'New Group' }) }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "grid gap-1.5", children: [jsx(Label, { htmlFor: "g-name", children: isTeam ? 'Team Name' : 'Group Name' }), jsx(Input, { id: "g-name", value: form.name, onChange: (e) => setForm({ ...form, name: e.target.value }), placeholder: isTeam ? 'Enter team name' : 'Enter group name', required: true })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label, { htmlFor: "g-desc", children: "Description" }), jsx(Input, { id: "g-desc", value: form.description, onChange: (e) => setForm({ ...form, description: e.target.value }), placeholder: isTeam ? 'Enter team description' : 'Enter group description' })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label, { children: isTeam ? 'Team Members' : 'Group Members' }), jsx("div", { className: "space-y-2", children: members.length > 0 ? (jsx("div", { className: "space-y-2 max-h-48 overflow-y-auto border border-gray-200 dark:border-gray-700 rounded-md p-2", children: members.map((member) => (jsxs("div", { className: "flex items-center justify-between bg-gray-50 dark:bg-gray-800 p-2 rounded-md", children: [jsxs("div", { className: "flex flex-col", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: member.name || member.username }), member.email && (jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: member.email }))] }), jsx(Button$1, { type: "button", variant: "ghost", size: "sm", onClick: () => removeMember(member.id), className: "h-8 w-8 p-0 text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-900/20", "aria-label": `Remove ${member.name}`, children: jsx(X$2, { className: "h-4 w-4" }) })] }, member.id))) })) : (jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400 p-4 text-center border border-dashed border-gray-300 dark:border-gray-600 rounded-md", children: "No members added yet" })) })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label, { htmlFor: "user-search", children: "Add Members" }), jsxs("div", { className: "relative", children: [jsx(Input, { id: "user-search", value: userSearch, onChange: (e) => {
126727
126743
  setUserSearch(e.target.value);
126728
126744
  setShowUserSearch(e.target.value.length > 0);
126729
126745
  }, onFocus: () => setShowUserSearch(userSearch.length > 0), placeholder: "Type to search users...", className: "w-full" }), showUserSearch && availableUsers.length > 0 && (jsx("div", { className: "absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg max-h-48 overflow-y-auto z-50", children: availableUsers.map((user) => (jsxs("button", { type: "button", onClick: () => {
@@ -126734,7 +126750,7 @@ function GroupsTab({ tenant, isTeam = false, hasInviteUserPermission = false, ha
126734
126750
  email: user.email,
126735
126751
  username: user.username,
126736
126752
  });
126737
- }, className: "w-full text-left px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 flex flex-col", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: user.name }), jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: user.email })] }, user.user_id))) })), showUserSearch && userSearch.length > 2 && availableUsers.length === 0 && (jsx("div", { className: "absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg p-3 z-50", children: jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: "No users found" }) }))] }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Type at least 3 characters to search for users" })] })] }), formError && (jsx("div", { className: "mt-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-md", children: jsx("p", { className: "text-sm text-red-600 dark:text-red-400", children: formError }) })), jsxs(DialogFooter, { className: "mt-6", children: [jsx(Button$1, { variant: "outline", onClick: () => setIsOpen(false), children: "Cancel" }), (!isTeam || !editing || (isTeam && hasEditTeamPermission)) && (jsx(TooltipProvider, { children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, children: jsxs(Button$1, { onClick: onSubmit, disabled: isSubmitting || (!!editing && (entityDetails === null || entityDetails === void 0 ? void 0 : entityDetails.is_internal)), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white", children: [isSubmitting ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin mr-2", "aria-hidden": "true" })) : null, editing
126753
+ }, className: "w-full text-left px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 flex flex-col", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: user.name }), jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: user.email })] }, user.user_id))) })), showUserSearch && userSearch.length > 2 && availableUsers.length === 0 && (jsx("div", { className: "absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg p-3 z-50", children: jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: "No users found" }) }))] }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Type at least 3 characters to search for users" })] })] }), formError && (jsx("div", { className: "mt-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-md", children: jsx("p", { className: "text-sm text-red-600 dark:text-red-400", children: formError }) })), jsxs(DialogFooter, { className: "mt-6", children: [jsx(Button$1, { variant: "outline", onClick: closeDialog, children: "Cancel" }), (!isTeam || !editing || (isTeam && hasEditTeamPermission)) && (jsx(TooltipProvider, { children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, children: jsxs(Button$1, { onClick: onSubmit, disabled: isSubmitting || (!!editing && (entityDetails === null || entityDetails === void 0 ? void 0 : entityDetails.is_internal)), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white", children: [isSubmitting ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin mr-2", "aria-hidden": "true" })) : null, editing
126738
126754
  ? isTeam
126739
126755
  ? 'Save Team'
126740
126756
  : 'Save Group'
@@ -126755,7 +126771,7 @@ function RolesTab({ tenant }) {
126755
126771
  platformKey: tenant,
126756
126772
  page,
126757
126773
  pageSize: 10,
126758
- ...(debouncedSearchQuery.length > 3 && { name: debouncedSearchQuery }),
126774
+ ...(debouncedSearchQuery.length > 2 && { name: debouncedSearchQuery }),
126759
126775
  });
126760
126776
  const [createRole] = useCreateRbacRoleMutation();
126761
126777
  const [updateRole] = useUpdateRbacRoleMutation();
@@ -126763,7 +126779,7 @@ function RolesTab({ tenant }) {
126763
126779
  // Debounce search query
126764
126780
  useEffect(() => {
126765
126781
  const handler = setTimeout(() => {
126766
- if (searchQuery.length > 3) {
126782
+ if (searchQuery.length > 2) {
126767
126783
  setDebouncedSearchQuery(searchQuery);
126768
126784
  setPage(1); // Reset to first page on new search
126769
126785
  }
@@ -126905,7 +126921,7 @@ function PoliciesTab({ tenant }) {
126905
126921
  platformKey: tenant,
126906
126922
  page,
126907
126923
  pageSize: 10,
126908
- ...(debouncedSearchQuery.length > 3 && { name: debouncedSearchQuery }),
126924
+ ...(debouncedSearchQuery.length > 2 && { name: debouncedSearchQuery }),
126909
126925
  });
126910
126926
  const [createPolicy] = useCreateRbacPolicyMutation();
126911
126927
  const [updatePolicy] = useUpdateRbacPolicyMutation();
@@ -126913,7 +126929,7 @@ function PoliciesTab({ tenant }) {
126913
126929
  // Debounce search query
126914
126930
  useEffect(() => {
126915
126931
  const handler = setTimeout(() => {
126916
- if (searchQuery.length > 3) {
126932
+ if (searchQuery.length > 2) {
126917
126933
  setDebouncedSearchQuery(searchQuery);
126918
126934
  setPage(1); // Reset to first page on new search
126919
126935
  }
@@ -126940,6 +126956,7 @@ function PoliciesTab({ tenant }) {
126940
126956
  const [selectedGroups, setSelectedGroups] = useState([]);
126941
126957
  const [originalGroups, setOriginalGroups] = useState([]);
126942
126958
  const [roleSearch, setRoleSearch] = useState('');
126959
+ const [debouncedRoleSearch, setDebouncedRoleSearch] = useState('');
126943
126960
  const [userSearch, setUserSearch] = useState('');
126944
126961
  const [groupSearch, setGroupSearch] = useState('');
126945
126962
  const [showRoleSearch, setShowRoleSearch] = useState(false);
@@ -126948,8 +126965,18 @@ function PoliciesTab({ tenant }) {
126948
126965
  const [deletingPolicyId, setDeletingPolicyId] = useState(null);
126949
126966
  // Fetch policy details when editing
126950
126967
  const { data: policyDetails } = useGetRbacPolicyDetailsQuery({ id: editingPolicyId, platform_key: tenant }, { skip: !editingPolicyId });
126951
- // Fetch roles for autocomplete
126952
- const { data: rolesData } = useGetRbacRolesQuery({ platformKey: tenant });
126968
+ // Debounce role search and query the roles endpoint with the search term
126969
+ useEffect(() => {
126970
+ const handler = setTimeout(() => {
126971
+ setDebouncedRoleSearch(roleSearch.trim());
126972
+ }, 300);
126973
+ return () => clearTimeout(handler);
126974
+ }, [roleSearch]);
126975
+ // Fetch roles for autocomplete (server-side filtered by name)
126976
+ const { data: rolesData } = useGetRbacRolesQuery({
126977
+ platformKey: tenant,
126978
+ ...(debouncedRoleSearch.length > 0 && { name: debouncedRoleSearch }),
126979
+ });
126953
126980
  // Fetch groups for autocomplete
126954
126981
  const { data: groupsData } = useGetRbacGroupsQuery({ platformKey: tenant });
126955
126982
  // Fetch users for search
@@ -126971,14 +126998,11 @@ function PoliciesTab({ tenant }) {
126971
126998
  }, [data]);
126972
126999
  // Calculate total pages
126973
127000
  const totalPages = data ? Math.ceil(data.count / 10) : 0;
126974
- // Filter available roles
127001
+ // Roles list (filtering happens server-side via the name query param)
126975
127002
  const availableRoles = useMemo(() => {
126976
127003
  var _a, _b, _c;
126977
- const rolesList = (_c = (_b = (_a = rolesData === null || rolesData === void 0 ? void 0 : rolesData.results) !== null && _a !== void 0 ? _a : rolesData === null || rolesData === void 0 ? void 0 : rolesData.data) !== null && _b !== void 0 ? _b : rolesData) !== null && _c !== void 0 ? _c : [];
126978
- if (!roleSearch)
126979
- return rolesList;
126980
- return rolesList.filter((role) => role.name.toLowerCase().includes(roleSearch.toLowerCase()));
126981
- }, [rolesData, roleSearch]);
127004
+ return (_c = (_b = (_a = rolesData === null || rolesData === void 0 ? void 0 : rolesData.results) !== null && _a !== void 0 ? _a : rolesData === null || rolesData === void 0 ? void 0 : rolesData.data) !== null && _b !== void 0 ? _b : rolesData) !== null && _c !== void 0 ? _c : [];
127005
+ }, [rolesData]);
126982
127006
  // Filter available groups
126983
127007
  const availableGroups = useMemo(() => {
126984
127008
  var _a, _b, _c;
@@ -127219,7 +127243,7 @@ function AlertsTab({ tenant }) {
127219
127243
  const [debouncedSearchQuery, setDebouncedSearchQuery] = useState('');
127220
127244
  useEffect(() => {
127221
127245
  const handler = setTimeout(() => {
127222
- if (searchQuery.length > 3) {
127246
+ if (searchQuery.length > 2) {
127223
127247
  setDebouncedSearchQuery(searchQuery);
127224
127248
  setPage(1);
127225
127249
  }
@@ -221369,7 +221393,7 @@ function Chat({ mode = 'default', isPreviewMode = false, hasBorder = true, isInC
221369
221393
  }
221370
221394
 
221371
221395
  function TasksTabToolbar({ taskDate, setTaskDate, setIsScheduleTaskDialogOpen, searchQuery, setSearchQuery, labels, }) {
221372
- return (jsxs("div", { className: "flex flex-col sm:flex-row items-center gap-4", children: [jsxs("div", { className: "relative flex-1 w-full", children: [jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-500" }), jsx(Input, { className: "pl-10 w-full", placeholder: labels.toolbar.searchPlaceholder, value: searchQuery, onChange: (e) => setSearchQuery(e.target.value) })] }), jsxs(Popover, { children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", className: "flex items-center gap-2 justify-start w-full sm:w-auto bg-transparent border-[#2563EB] text-[#2563EB]", children: [jsx(Calendar$1, { className: "h-4 w-4" }), jsx("span", { children: taskDate ? format(taskDate, 'MM/dd/yyyy') : labels.toolbar.selectDate })] }) }), jsx(PopoverContent, { className: "w-auto p-0", align: "start", portalled: false, children: jsx(Calendar, { mode: "single", selected: taskDate, onSelect: setTaskDate, classNames: {
221396
+ return (jsxs("div", { className: "flex flex-col sm:flex-row items-center gap-4", children: [jsxs("div", { className: "relative flex-1 w-full", children: [jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-500" }), jsx(Input, { className: "pl-10 w-full", placeholder: labels.toolbar.searchPlaceholder, value: searchQuery, onChange: (e) => setSearchQuery(e.target.value) })] }), jsxs(Popover, { children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", className: "flex items-center gap-2 justify-start w-full sm:w-auto bg-transparent", children: [jsx(Calendar$1, { className: "h-4 w-4" }), jsx("span", { children: taskDate ? format(taskDate, 'MM/dd/yyyy') : labels.toolbar.selectDate })] }) }), jsx(PopoverContent, { className: "w-auto p-0", align: "start", portalled: false, children: jsx(Calendar, { mode: "single", selected: taskDate, onSelect: setTaskDate, classNames: {
221373
221397
  day_button: 'data-[selected-single=true]:bg-[#2563EB] data-[selected-single=true]:text-white data-[range-start=true]:bg-[#2563EB] data-[range-start=true]:text-white data-[range-end=true]:bg-[#2563EB] data-[range-end=true]:text-white',
221374
221398
  today: 'bg-blue-50 text-[#2563EB] data-[selected=true]:bg-[#2563EB] data-[selected=true]:text-white',
221375
221399
  }, initialFocus: true }) })] }), jsxs(Button$1, { className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white font-medium w-full sm:w-auto", onClick: () => setIsScheduleTaskDialogOpen(true), children: [jsx(Plus, { className: "h-4 w-4 mr-2" }), labels.toolbar.scheduleTask] })] }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iblai/iblai-js",
3
- "version": "1.17.22",
3
+ "version": "1.17.25",
4
4
  "description": "Unified JavaScript SDK for IBL.ai — re-exports data-layer, web-containers, and web-utils under a single package",
5
5
  "type": "module",
6
6
  "engines": {
@@ -68,8 +68,8 @@
68
68
  "winston": "3.19.0",
69
69
  "@iblai/data-layer": "1.7.5",
70
70
  "@iblai/mcp": "1.5.8",
71
- "@iblai/web-containers": "1.8.16",
72
- "@iblai/web-utils": "1.10.10"
71
+ "@iblai/web-containers": "1.8.19",
72
+ "@iblai/web-utils": "1.10.11"
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@radix-ui/react-dialog": "^1.1.7",