diff --git a/apps/edr-freight-web/backoffice/src/pages/dashboard/user-management/PermissionsPage.tsx b/apps/edr-freight-web/backoffice/src/pages/dashboard/user-management/PermissionsPage.tsx
index d0d9a7867..10c5aba25 100644
--- a/apps/edr-freight-web/backoffice/src/pages/dashboard/user-management/PermissionsPage.tsx
+++ b/apps/edr-freight-web/backoffice/src/pages/dashboard/user-management/PermissionsPage.tsx
@@ -1,5 +1,12 @@
import { useEffect, useState } from "react";
import { isAxiosError } from "axios";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@edr/ui-common";
import { api } from "@/auth/http";
@@ -12,6 +19,13 @@ interface PermissionRecord {
id: string;
key: string;
name?: LocaleText;
+ applicationId?: string | null;
+}
+
+interface ApplicationRecord {
+ id: string;
+ key: string;
+ name?: LocaleText;
}
interface ListResponse {
@@ -21,6 +35,8 @@ interface ListResponse {
}
const PAGE_SIZE = 2000;
+const ALL_APPLICATIONS_VALUE = "all";
+const SYSTEM_APPLICATION_VALUE = "system";
const getLocaleLabel = (value?: LocaleText | null, fallback = "Unnamed") =>
value?.en ?? value?.am ?? fallback;
@@ -46,6 +62,8 @@ const sortPermissions = (items: PermissionRecord[]) =>
const PermissionsPage = () => {
const [permissions, setPermissions] = useState([]);
+ const [applications, setApplications] = useState([]);
+ const [selectedApplication, setSelectedApplication] = useState(ALL_APPLICATIONS_VALUE);
const [count, setCount] = useState(0);
const [loading, setLoading] = useState(true);
const [loadingMore, setLoadingMore] = useState(false);
@@ -54,26 +72,35 @@ const PermissionsPage = () => {
useEffect(() => {
let isMounted = true;
- const loadPermissions = async () => {
+ const loadPageData = async () => {
setLoading(true);
setErrorMessage(null);
try {
- const response = await api.get>("/permissions", {
- params: {
- skip: 0,
- take: PAGE_SIZE,
- },
- });
+ const [permissionsResponse, applicationsResponse] = await Promise.all([
+ api.get>("/permissions", {
+ params: {
+ skip: 0,
+ take: PAGE_SIZE,
+ },
+ }),
+ api.get>("/applications"),
+ ]);
if (!isMounted) {
return;
}
- const items = sortPermissions(getItems(response.data));
+ const items = sortPermissions(getItems(permissionsResponse.data));
+ const applicationItems = [...getItems(applicationsResponse.data)].sort((left, right) =>
+ getLocaleLabel(left.name, left.key).localeCompare(
+ getLocaleLabel(right.name, right.key),
+ ),
+ );
setPermissions(items);
- setCount(response.data.count ?? items.length);
+ setApplications(applicationItems);
+ setCount(permissionsResponse.data.count ?? items.length);
} catch (error) {
if (!isMounted) {
return;
@@ -91,7 +118,7 @@ const PermissionsPage = () => {
}
};
- void loadPermissions();
+ void loadPageData();
return () => {
isMounted = false;
@@ -99,6 +126,17 @@ const PermissionsPage = () => {
}, []);
const hasMore = count > permissions.length;
+ const filteredPermissions = permissions.filter((permission) => {
+ if (selectedApplication === ALL_APPLICATIONS_VALUE) {
+ return true;
+ }
+
+ if (selectedApplication === SYSTEM_APPLICATION_VALUE) {
+ return !permission.applicationId;
+ }
+
+ return permission.applicationId === selectedApplication;
+ });
const handleLoadMore = async () => {
setLoadingMore(true);
@@ -142,11 +180,36 @@ const PermissionsPage = () => {
- {count || permissions.length} permissions
+ {filteredPermissions.length} permissions
+
+
+
+ Application
+
+
+
+
+ Filter the IAM permission catalog by application, or view the shared system permissions that do not belong to any application.
+
+
+
{loading ? (
Loading permissions...
@@ -155,9 +218,9 @@ const PermissionsPage = () => {
{errorMessage}
- ) : permissions.length ? (
+ ) : filteredPermissions.length ? (
- {permissions.map((permission) => (
+ {filteredPermissions.map((permission) => (
{
) : (
- No permissions are available in the system.
+ No permissions match the selected application.
)}