diff --git a/changes/10879-api-only-user-badge b/changes/10879-api-only-user-badge
new file mode 100644
index 0000000000..635f5fa738
--- /dev/null
+++ b/changes/10879-api-only-user-badge
@@ -0,0 +1 @@
+- User management table informs which users only have API accesss
diff --git a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/MembersPageTableConfig.tsx b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/MembersPageTableConfig.tsx
index 0a289eebdc..1f62ec5dd4 100644
--- a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/MembersPageTableConfig.tsx
+++ b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/MembersPageTableConfig.tsx
@@ -1,6 +1,8 @@
import React from "react";
+import ReactTooltip from "react-tooltip";
import TextCell from "components/TableContainer/DataTable/TextCell/TextCell";
import DropdownCell from "components/TableContainer/DataTable/DropdownCell";
+import CustomLink from "components/CustomLink";
import { IUser } from "interfaces/user";
import { ITeam } from "interfaces/team";
import { IDropdownOption } from "interfaces/dropdownOption";
@@ -64,9 +66,54 @@ const generateTableHeaders = (
disableSortBy: true,
sortType: "caseInsensitive",
accessor: "name",
- Cell: (cellProps: ICellProps) => (
-
- ),
+ Cell: (cellProps: ICellProps) => {
+ const formatter = (val: string) => {
+ const apiOnlyUser =
+ "api_only" in cellProps.row.original
+ ? cellProps.row.original.api_only
+ : false;
+
+ return (
+ <>
+ {val}
+ {apiOnlyUser && (
+ <>
+
+ API
+
+
+ <>
+ This user was created using fleetctl and
+
only has API access.{" "}
+
+ >
+
+ >
+ )}
+ >
+ );
+ };
+
+ return ;
+ },
},
{
title: "Role",
@@ -137,6 +184,7 @@ const enhanceMembersData = (
global_role: user.global_role,
actions: generateActionDropdownOptions(),
id: user.id,
+ api_only: user.api_only,
};
});
};
diff --git a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/_styles.scss b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/_styles.scss
index 96e77ae4f7..07e5742d53 100644
--- a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/_styles.scss
+++ b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/_styles.scss
@@ -6,6 +6,10 @@
margin: 0;
}
+ &__api-only-user {
+ @include grey-badge;
+ }
+
.data-table-block {
.data-table__table {
thead {
diff --git a/frontend/pages/admin/UserManagementPage/_styles.scss b/frontend/pages/admin/UserManagementPage/_styles.scss
index b4730838e3..163dfa6e25 100644
--- a/frontend/pages/admin/UserManagementPage/_styles.scss
+++ b/frontend/pages/admin/UserManagementPage/_styles.scss
@@ -9,4 +9,8 @@
&__sandbox-demo-message {
margin-top: 3.5rem;
}
+
+ &__api-only-user {
+ @include grey-badge;
+ }
}
diff --git a/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTableConfig.tsx b/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTableConfig.tsx
index 8c2b52f445..22fb5ceacf 100644
--- a/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTableConfig.tsx
+++ b/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTableConfig.tsx
@@ -1,8 +1,10 @@
import React from "react";
+import ReactTooltip from "react-tooltip";
import HeaderCell from "components/TableContainer/DataTable/HeaderCell/HeaderCell";
import StatusIndicator from "components/StatusIndicator";
import TextCell from "components/TableContainer/DataTable/TextCell/TextCell";
+import CustomLink from "components/CustomLink";
import { IInvite } from "interfaces/invite";
import { IUser } from "interfaces/user";
import { IDropdownOption } from "interfaces/dropdownOption";
@@ -55,6 +57,7 @@ export interface IUserTableData {
actions: IDropdownOption[];
id: number;
type: string;
+ api_only: boolean;
}
// NOTE: cellProps come from react-table
@@ -69,9 +72,54 @@ const generateTableHeaders = (
Header: "Name",
disableSortBy: true,
accessor: "name",
- Cell: (cellProps: ICellProps) => (
-
- ),
+ Cell: (cellProps: ICellProps) => {
+ const formatter = (val: string) => {
+ const apiOnlyUser =
+ "api_only" in cellProps.row.original
+ ? cellProps.row.original.api_only
+ : false;
+
+ return (
+ <>
+ {val}
+ {apiOnlyUser && (
+ <>
+
+ API
+
+
+ <>
+ This user was created using fleetctl and
+
only has API access.{" "}
+
+ >
+
+ >
+ )}
+ >
+ );
+ };
+
+ return ;
+ },
},
{
title: "Role",
@@ -206,6 +254,7 @@ const enhanceUserData = (
),
id: user.id,
type: "user",
+ api_only: user.api_only,
};
});
};
@@ -221,6 +270,7 @@ const enhanceInviteData = (invites: IInvite[]): IUserTableData[] => {
actions: generateActionDropdownOptions(false, true, invite.sso_enabled),
id: invite.id,
type: "invite",
+ api_only: false, // api only users are created through fleetctl and not invites
};
});
};
diff --git a/frontend/styles/var/mixins.scss b/frontend/styles/var/mixins.scss
index b37eb690c8..a6cfb7e4aa 100644
--- a/frontend/styles/var/mixins.scss
+++ b/frontend/styles/var/mixins.scss
@@ -36,3 +36,14 @@ $max-width: 2560px;
margin: 0;
padding: $pad-xxlarge 0 54px 0;
}
+
+@mixin grey-badge {
+ background-color: $ui-fleet-black-25;
+ color: $core-white;
+ font-size: $xx-small;
+ font-weight: 700;
+ padding: 0 $pad-xsmall;
+ border-radius: $border-radius;
+ position: relative;
+ margin-left: $pad-xsmall;
+}