Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 9 additions & 31 deletions frontend/src/components/pages/acls/acl-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import { api, rolesApi } from '../../../state/backend-api';
import { AclRequestDefault } from '../../../state/rest-interfaces';
import { Features } from '../../../state/supported-features';
import { uiState } from '../../../state/ui-state';
import { getSearchRegex } from '../../../utils/regex';
import { Code as CodeEl, DefaultSkeleton } from '../../../utils/tsx-utils';
import { FeatureLicenseNotification } from '../../license/feature-license-notification';
import { NullFallbackBoundary } from '../../misc/null-fallback-boundary';
Expand Down Expand Up @@ -284,17 +285,10 @@ const PermissionsListTab = () => {
}

const usersFiltered = users.filter((u) => {
const filter = searchQuery;
if (!filter) {
if (!searchQuery) {
return true;
}

try {
const quickSearchRegExp = new RegExp(filter, 'i');
return u.name.match(quickSearchRegExp);
} catch {
return false;
}
return u.name.match(getSearchRegex(searchQuery));
});

return (
Expand Down Expand Up @@ -384,17 +378,10 @@ const UsersTab = ({ isAdminApiConfigured }: { isAdminApiConfigured: boolean }) =
}));

const usersFiltered = users.filter((u) => {
const filter = searchQuery;
if (!filter) {
if (!searchQuery) {
return true;
}

try {
const quickSearchRegExp = new RegExp(filter, 'i');
return u.name.match(quickSearchRegExp);
} catch {
return false;
}
return u.name.match(getSearchRegex(searchQuery));
});

if (isError && error) {
Expand Down Expand Up @@ -568,16 +555,10 @@ const RolesTab = () => {
const [searchQuery, setSearchQuery] = useState('');

const roles = (rolesApi.roles ?? []).filter((u) => {
const filter = searchQuery;
if (!filter) {
if (!searchQuery) {
return true;
}
try {
const quickSearchRegExp = new RegExp(filter, 'i');
return u.match(quickSearchRegExp);
} catch {
return false;
}
return u.match(getSearchRegex(searchQuery));
});

const rolesWithMembers = roles.map((r) => {
Expand Down Expand Up @@ -730,11 +711,8 @@ const AclsTab = (_: { principalGroups: AclPrincipalGroup[] }) => {

let groups = principalGroups?.filter((g) => g.principalType === 'User') || [];

try {
const quickSearchRegExp = new RegExp(searchQuery, 'i');
groups = groups?.filter((aclGroup) => aclGroup.principalName.match(quickSearchRegExp));
} catch (_e) {
// Invalid regex, skip filtering
if (searchQuery) {
groups = groups.filter((aclGroup) => aclGroup.principalName.match(getSearchRegex(searchQuery)));
}

if (isError && error) {
Expand Down
9 changes: 3 additions & 6 deletions frontend/src/components/pages/acls/role-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { AclPrincipalGroupPermissionsTable } from './user-details';
import { appGlobal } from '../../../state/app-global';
import { api, type RolePrincipal, rolesApi } from '../../../state/backend-api';
import { AclRequestDefault } from '../../../state/rest-interfaces';
import { getSearchRegex } from '../../../utils/regex';
import { DefaultSkeleton } from '../../../utils/tsx-utils';
import PageContent from '../../misc/page-content';
import { PageComponent, type PageInitHelper, type PageProps } from '../page';
Expand Down Expand Up @@ -85,12 +86,8 @@ class RoleDetailsPage extends PageComponent<{ roleName: string }> {
);

let members = rolesApi.roleMembers.get(this.roleName) ?? [];
try {
const quickSearchRegExp = new RegExp(this.principalSearch, 'i');
members = members.filter(({ name }) => name.match(quickSearchRegExp));
} catch (_e) {
// biome-ignore lint/suspicious/noConsole: warning for invalid user input
console.warn('Invalid expression');
if (this.principalSearch) {
members = members.filter(({ name }) => name.match(getSearchRegex(this.principalSearch)));
}

const numberOfPrincipals = rolesApi.roleMembers.get(this.roleName)?.length ?? 0;
Expand Down
12 changes: 4 additions & 8 deletions frontend/src/components/pages/admin/admin-users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { UserCircleIcon } from 'components/icons';
import { makeObservable, observable } from 'mobx';

import { RoleComponent } from './admin-roles';
import { getSearchRegex } from '../../../utils/regex';
import { DefaultSkeleton } from '../../../utils/tsx-utils';

@observer
Expand All @@ -39,14 +40,9 @@ export class AdminUsers extends Component<Record<string, never>> {

let users = api.adminInfo.users;

try {
const quickSearchRegExp = new RegExp(this.quickSearch, 'i');
users = users.filter(
(u) => u.internalIdentifier.match(quickSearchRegExp) || u.oauthUserId.match(quickSearchRegExp)
);
} catch (_e) {
// biome-ignore lint/suspicious/noConsole: intentional console usage
console.warn('Invalid expression');
if (this.quickSearch) {
const searchRegex = getSearchRegex(this.quickSearch);
users = users.filter((u) => u.internalIdentifier.match(searchRegex) || u.oauthUserId.match(searchRegex));
}

const table = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,12 +318,7 @@ export const AIAgentConfigurationTab = () => {
const [expandedSubagent, setExpandedSubagent] = useState<string | undefined>(undefined);

// Get available MCP servers
const availableMcpServers = useMemo(() => {
if (!mcpServersData?.mcpServers || mcpServersData.mcpServers.length === 0) {
return [];
}
return mcpServersData.mcpServers;
}, [mcpServersData]);
const availableMcpServers = mcpServersData?.mcpServers ?? [];

// Get available secrets for API key dropdown
const availableSecrets = useMemo(() => {
Expand Down Expand Up @@ -1176,10 +1171,7 @@ export const AIAgentConfigurationTab = () => {
value={displayData.model}
/>
) : (
<Select
onValueChange={(value) => updateField({ model: value })}
value={displayData.model}
>
<Select onValueChange={(value) => updateField({ model: value })} value={displayData.model}>
<SelectTrigger>
<SelectValue>
{Boolean(displayData.model) && detectProvider(displayData.model) ? (
Expand Down
13 changes: 4 additions & 9 deletions frontend/src/components/pages/connect/cluster-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { appGlobal } from '../../../state/app-global';
import { api } from '../../../state/backend-api';
import type { ClusterAdditionalInfo, ClusterConnectorInfo } from '../../../state/rest-interfaces';
import { uiSettings } from '../../../state/ui';
import { getSearchRegex } from '../../../utils/regex';
import { DefaultSkeleton } from '../../../utils/tsx-utils';
import PageContent from '../../misc/page-content';
import SearchBar from '../../misc/search-bar';
Expand Down Expand Up @@ -53,15 +54,9 @@ class KafkaClusterDetails extends PageComponent<{ clusterName: string }> {
api.refreshClusterAdditionalInfo(clusterName, force);
}

isFilterMatch(filter: string, item: ClusterConnectorInfo): boolean {
try {
const quickSearchRegExp = new RegExp(uiSettings.connectorsList.quickSearch, 'i');
return Boolean(item.name.match(quickSearchRegExp)) || Boolean(item.class.match(quickSearchRegExp));
} catch (_e) {
// biome-ignore lint/suspicious/noConsole: intentional console usage
console.warn('Invalid expression');
return item.name.toLowerCase().includes(filter.toLowerCase());
}
isFilterMatch(_filter: string, item: ClusterConnectorInfo): boolean {
const searchRegex = getSearchRegex(uiSettings.connectorsList.quickSearch);
return Boolean(item.name.match(searchRegex)) || Boolean(item.class.match(searchRegex));
}

render() {
Expand Down
11 changes: 4 additions & 7 deletions frontend/src/components/pages/connect/overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { api, rpcnSecretManagerApi } from '../../../state/backend-api';
import type { ClusterConnectorInfo, ClusterConnectors, ClusterConnectorTaskInfo } from '../../../state/rest-interfaces';
import { Features } from '../../../state/supported-features';
import { uiSettings } from '../../../state/ui';
import { getSearchRegex } from '../../../utils/regex';
import { Code, DefaultSkeleton } from '../../../utils/tsx-utils';
import PageContent from '../../misc/page-content';
import SearchBar from '../../misc/search-bar';
Expand Down Expand Up @@ -289,13 +290,9 @@ const TabConnectors = observer(() => {
filteredResults: [],
}));

const isFilterMatch = (filter: string, item: ConnectorType): boolean => {
try {
const quickSearchRegExp = new RegExp(uiSettings.clusterOverview.connectorsList.quickSearch, 'i');
return Boolean(item.name.match(quickSearchRegExp)) || Boolean(item.class.match(quickSearchRegExp));
} catch (_e) {
return item.name.toLowerCase().includes(filter.toLowerCase());
}
const isFilterMatch = (_filter: string, item: ConnectorType): boolean => {
const searchRegex = getSearchRegex(uiSettings.clusterOverview.connectorsList.quickSearch);
return Boolean(item.name.match(searchRegex)) || Boolean(item.class.match(searchRegex));
};

return (
Expand Down
10 changes: 4 additions & 6 deletions frontend/src/components/pages/consumers/group-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { api } from '../../../state/backend-api';
import type { GroupDescription } from '../../../state/rest-interfaces';
import { uiSettings } from '../../../state/ui';
import { editQuery } from '../../../utils/query-helper';
import { getSearchRegex } from '../../../utils/regex';
import { DefaultSkeleton } from '../../../utils/tsx-utils';
import { BrokerList } from '../../misc/broker-list';
import PageContent from '../../misc/page-content';
Expand Down Expand Up @@ -75,15 +76,12 @@ class GroupList extends PageComponent {

let groups = Array.from(api.consumerGroups.values());

try {
const quickSearchRegExp = new RegExp(uiSettings.consumerGroupList.quickSearch, 'i');
if (uiSettings.consumerGroupList.quickSearch) {
const searchRegex = getSearchRegex(uiSettings.consumerGroupList.quickSearch);
groups = groups.filter(
(groupDescription) =>
groupDescription.groupId.match(quickSearchRegExp) || groupDescription.protocol.match(quickSearchRegExp)
groupDescription.groupId.match(searchRegex) || groupDescription.protocol.match(searchRegex)
);
} catch (_e) {
// biome-ignore lint/suspicious/noConsole: intentional console usage
console.warn('Invalid expression');
}

const stateGroups = groups.groupInto((g) => g.state);
Expand Down
17 changes: 4 additions & 13 deletions frontend/src/components/pages/rp-connect/pipelines-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { appGlobal } from '../../../state/app-global';
import { pipelinesApi } from '../../../state/backend-api';
import { Features } from '../../../state/supported-features';
import { uiSettings } from '../../../state/ui';
import { getSearchRegex } from '../../../utils/regex';
import { DefaultSkeleton } from '../../../utils/tsx-utils';
import { encodeURIComponentPercents } from '../../../utils/utils';
import PageContent from '../../misc/page-content';
Expand Down Expand Up @@ -165,25 +166,15 @@ class RpConnectPipelinesList extends PageComponent<{}> {
return DefaultSkeleton;
}

const filter = uiSettings.pipelinesList.quickSearch;
const filteredPipelines = (pipelinesApi.pipelines ?? [])
?.filter((pipeline) => pipeline?.tags?.__redpanda_cloud_pipeline_type !== 'agent') // Ensure we do not show the agents
.filter((u) => {
const filter = uiSettings.pipelinesList.quickSearch;
if (!filter) {
return true;
}
try {
const quickSearchRegExp = new RegExp(filter, 'i');
if (u.id.match(quickSearchRegExp)) {
return true;
}
if (u.displayName.match(quickSearchRegExp)) {
return true;
}
return false;
} catch {
return false;
}
const searchRegex = getSearchRegex(filter);
return u.id.match(searchRegex) || u.displayName.match(searchRegex);
});

return (
Expand Down
13 changes: 3 additions & 10 deletions frontend/src/components/pages/rp-connect/secrets/secrets-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { appGlobal } from '../../../../state/app-global';
import { rpcnSecretManagerApi } from '../../../../state/backend-api';
import { Features } from '../../../../state/supported-features';
import { uiSettings } from '../../../../state/ui';
import { getSearchRegex } from '../../../../utils/regex';
import PageContent from '../../../misc/page-content';
import Section from '../../../misc/section';
import { PageComponent, type PageInitHelper } from '../../page';
Expand Down Expand Up @@ -86,20 +87,12 @@ class RpConnectSecretsList extends PageComponent {
}

render() {
const filter = uiSettings.rpcnSecretList.quickSearch;
const filteredSecrets = (rpcnSecretManagerApi.secrets ?? []).filter((u) => {
const filter = uiSettings.rpcnSecretList.quickSearch;
if (!filter) {
return true;
}
try {
const quickSearchRegExp = new RegExp(filter, 'i');
if (u.id.match(quickSearchRegExp)) {
return true;
}
return false;
} catch {
return false;
}
return u.id.match(getSearchRegex(filter));
});

return (
Expand Down
24 changes: 14 additions & 10 deletions frontend/src/components/pages/rp-connect/utils/yaml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,16 @@ const mergeCacheResource = (doc: Document.Parsed, newConfigObject: Partial<Conne
let newResource = cacheConfigObj?.cache_resources?.[0] as Record<string, unknown> | undefined;

if (newResource) {
const existingLabels = Array.isArray(cacheResources)
? (cacheResources as Record<string, unknown>[]).map((r) => r?.label).filter(Boolean)
: [];
const existingLabelsSet = new Set(
Array.isArray(cacheResources)
? (cacheResources as Record<string, unknown>[]).map((r) => r?.label).filter(Boolean)
: []
);

if (existingLabels.includes(newResource.label as string)) {
if (existingLabelsSet.has(newResource.label as string)) {
let counter = 1;
let uniqueLabel = `${newResource.label}_${counter}`;
while (existingLabels.includes(uniqueLabel)) {
while (existingLabelsSet.has(uniqueLabel)) {
counter += 1;
uniqueLabel = `${newResource.label}_${counter}`;
}
Expand All @@ -60,14 +62,16 @@ const mergeRateLimitResource = (doc: Document.Parsed, newConfigObject: Partial<C
let newResource = rateLimitConfigObj?.rate_limit_resources?.[0] as Record<string, unknown> | undefined;

if (newResource) {
const existingLabels = Array.isArray(rateLimitResources)
? (rateLimitResources as Record<string, unknown>[]).map((r) => r?.label).filter(Boolean)
: [];
const existingLabelsSet = new Set(
Array.isArray(rateLimitResources)
? (rateLimitResources as Record<string, unknown>[]).map((r) => r?.label).filter(Boolean)
: []
);

if (existingLabels.includes(newResource.label as string)) {
if (existingLabelsSet.has(newResource.label as string)) {
let counter = 1;
let uniqueLabel = `${newResource.label}_${counter}`;
while (existingLabels.includes(uniqueLabel)) {
while (existingLabelsSet.has(uniqueLabel)) {
counter += 1;
uniqueLabel = `${newResource.label}_${counter}`;
}
Expand Down
12 changes: 3 additions & 9 deletions frontend/src/components/pages/schemas/schema-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import { api } from '../../../state/backend-api';
import type { SchemaRegistrySubject } from '../../../state/rest-interfaces';
import { uiSettings } from '../../../state/ui';
import { uiState } from '../../../state/ui-state';
// Utility components and functions
import { getSearchRegex } from '../../../utils/regex';
import { Button, InlineSkeleton } from '../../../utils/tsx-utils';
import { encodeURIComponentPercents } from '../../../utils/utils';
// Layout components
Expand Down Expand Up @@ -162,14 +162,8 @@ const SchemaList: FC = () => {
// Find by schema ID
const filterAsNumber = Number(searchQuery.trim());
if (Number.isNaN(filterAsNumber)) {
// Find by regex or string matching
try {
const quickSearchRegExp = new RegExp(searchQuery, 'i');
subjects = subjects.filter((subject) => Boolean(subject.name.match(quickSearchRegExp)));
} catch (_e) {
const searchLower = searchQuery.toLowerCase();
subjects = subjects.filter((subject) => subject.name.toLowerCase().includes(searchLower));
}
// Find by string matching
subjects = subjects.filter((subject) => Boolean(subject.name.match(getSearchRegex(searchQuery))));
} else {
const matchingSubjectNames = new Set(schemaUsages?.map((s) => s.subject) ?? []);
subjects = subjects.filter((subject) => matchingSubjectNames.has(subject.name));
Expand Down
Loading
Loading