diff --git a/changes/50083-added-to-fleet-column b/changes/50083-added-to-fleet-column
new file mode 100644
index 0000000000..2b14852f67
--- /dev/null
+++ b/changes/50083-added-to-fleet-column
@@ -0,0 +1,2 @@
+* Added a sortable "Added to Fleet" column to the hosts table, showing when each host last enrolled with Fleet.
+* Fixed sort direction on the "Last seen" and "Last fetched" columns of the hosts table so that sort descending puts the oldest date (biggest "days ago" number) first, matching the visible duration rather than the underlying timestamp.
diff --git a/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx b/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx
index 0a2ad02a7e..fccd076eb4 100644
--- a/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx
@@ -732,6 +732,37 @@ const allHostTableHeaders = (teamId?: number): IHostTableColumnConfig[] => [
);
},
},
+ // Added to Fleet
+ {
+ title: "Added to Fleet",
+ Header: (cellProps: IHostTableHeaderProps) => {
+ const titleWithToolTip = (
+
+ The last time the
host enrolled with Fleet.
+ >
+ }
+ >
+ Added to Fleet
+
+ );
+ return (
+
+ );
+ },
+ accessor: "last_enrolled_at",
+ id: "last_enrolled_at",
+ Cell: (cellProps: IHostTableStringCellProps) => (
+
+ ),
+ },
];
const defaultHiddenColumns = [
@@ -752,6 +783,7 @@ const defaultHiddenColumns = [
"seen_time",
"hardware_model",
"hardware_serial",
+ "last_enrolled_at",
];
/**
diff --git a/frontend/pages/hosts/ManageHostsPage/HostsPageConfig.tsx b/frontend/pages/hosts/ManageHostsPage/HostsPageConfig.tsx
index c2135e688c..3c52696fa2 100644
--- a/frontend/pages/hosts/ManageHostsPage/HostsPageConfig.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/HostsPageConfig.tsx
@@ -1,4 +1,4 @@
-import { HOSTS_QUERY_PARAMS } from "services/entities/hosts";
+import { HOSTS_QUERY_PARAMS, ISortOption } from "services/entities/hosts";
export const MANAGE_HOSTS_PAGE_FILTER_KEYS = [
"query",
@@ -68,6 +68,25 @@ export const DEFAULT_SORT_DIRECTION = "asc";
export const DEFAULT_PAGE_SIZE = 50;
export const DEFAULT_PAGE_INDEX = 0;
+// Columns rendered as "N days ago" durations. Sort direction is inverted at
+// the API boundary so arrow-down = biggest days-ago (oldest date) first —
+// matching the visible number rather than the underlying timestamp.
+export const TIME_AGO_SORT_HEADERS = new Set([
+ "seen_time",
+ "detail_updated_at",
+ "last_restarted_at",
+ "last_enrolled_at",
+]);
+
+export const toApiSortBy = (sortBy: ISortOption[]): ISortOption[] =>
+ sortBy.map((s) => {
+ if (!TIME_AGO_SORT_HEADERS.has(s.key)) return s;
+ return {
+ key: s.key,
+ direction: s.direction === "asc" ? "desc" : "asc",
+ };
+ });
+
export const hostSelectStatuses = (isPremiumTier: boolean) => {
const baseStatuses = [
{
diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
index a4d2f3799e..39defbceb7 100644
--- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
@@ -115,6 +115,7 @@ import {
DEFAULT_SORT_DIRECTION,
DEFAULT_PAGE_SIZE,
DEFAULT_PAGE_INDEX,
+ toApiSortBy,
hostSelectStatuses,
MANAGE_HOSTS_PAGE_FILTER_KEYS,
MANAGE_HOSTS_PAGE_LABEL_INCOMPATIBLE_QUERY_PARAMS,
@@ -336,6 +337,7 @@ const ManageHostsPage = ({
);
const [searchQuery, setSearchQuery] = useState(initialQuery);
const [sortBy, setSortBy] = useState(initialSortBy);
+ const apiSortBy = useMemo(() => toApiSortBy(sortBy), [sortBy]);
const [tableQueryData, setTableQueryData] = useState();
const [isUpdating, setIsUpdating] = useState(false);
@@ -668,7 +670,7 @@ const ManageHostsPage = ({
scope: "hosts",
selectedLabels,
globalFilter: searchQuery,
- sortBy,
+ sortBy: apiSortBy,
teamId: teamIdForApi,
policyId,
policyResponse,
@@ -1188,18 +1190,10 @@ const ManageHostsPage = ({
let sort = sortBy;
if (sortHeader) {
- let direction = sortDirection;
- if (sortHeader === "last_restarted_at") {
- if (sortDirection === "asc") {
- direction = "desc";
- } else {
- direction = "asc";
- }
- }
sort = [
{
key: sortHeader,
- direction: direction || DEFAULT_SORT_DIRECTION,
+ direction: sortDirection || DEFAULT_SORT_DIRECTION,
},
];
} else if (!sortBy.length) {
@@ -1780,7 +1774,7 @@ const ManageHostsPage = ({
let options = {
selectedLabels,
globalFilter: searchQuery,
- sortBy,
+ sortBy: apiSortBy,
teamId: teamIdForApi,
policyId,
policyResponse,
@@ -1847,7 +1841,7 @@ const ManageHostsPage = ({
teamIdForApi,
selectedLabels,
searchQuery,
- sortBy,
+ apiSortBy,
policyId,
policyResponse,
macSettingsStatus,