diff --git a/src/components/profile-data-table.tsx b/src/components/profile-data-table.tsx
index 00521bb..2ff9e06 100644
--- a/src/components/profile-data-table.tsx
+++ b/src/components/profile-data-table.tsx
@@ -51,6 +51,12 @@ import {
CommandItem,
CommandList,
} from "@/components/ui/command";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
import {
Popover,
PopoverContent,
@@ -2381,28 +2387,89 @@ export function ProfilesDataTable({
);
},
},
+ {
+ // Hidden, sort-only column so profiles can be sorted by creation date
+ // without showing a Created column in the table (issue #454). Kept
+ // hidden via columnVisibility; sorting still works on hidden columns.
+ id: "created_at",
+ accessorFn: (row) => row.created_at ?? 0,
+ enableSorting: true,
+ enableHiding: true,
+ sortingFn: "basic",
+ header: () => null,
+ cell: () => null,
+ },
{
accessorKey: "name",
// The only column without a fixed width: table-fixed hands it all
// remaining space as the window grows or shrinks.
meta: { flexWidth: true },
- header: ({ column, table }) => {
+ // The Name header doubles as the sort control: clicking opens a menu to
+ // sort by name (A–Z / Z–A) or by creation date (newest / oldest), so
+ // creation-date sorting needs no visible column.
+ header: ({ table }) => {
const meta = table.options.meta as TableMeta;
+ const sort = table.getState().sorting[0];
+ const isActive = (id: string, desc: boolean) =>
+ sort?.id === id && !!sort.desc === desc;
return (
-
+
+
+
+
+
+
+ table.setSorting([{ id: "name", desc: false }])
+ }
+ >
+ {isActive("name", false) && (
+
+ )}
+ {meta.t("profiles.sort.nameAsc")}
+
+ table.setSorting([{ id: "name", desc: true }])}
+ >
+ {isActive("name", true) && (
+
+ )}
+ {meta.t("profiles.sort.nameDesc")}
+
+
+ table.setSorting([{ id: "created_at", desc: true }])
+ }
+ >
+ {isActive("created_at", true) && (
+
+ )}
+ {meta.t("profiles.sort.newest")}
+
+
+ table.setSorting([{ id: "created_at", desc: false }])
+ }
+ >
+ {isActive("created_at", false) && (
+
+ )}
+ {meta.t("profiles.sort.oldest")}
+
+
+
);
},
enableSorting: true,
@@ -2934,7 +3001,7 @@ export function ProfilesDataTable({
// expendable first); their data stays reachable via the profile info
// dialog. Visibility (not CSS hiding) so table-fixed reclaims the width.
const [columnVisibility, setColumnVisibility] =
- React.useState({});
+ React.useState({ created_at: false });
// Content columns grow proportionally with the container but never drop
// below the compact-layout floor; the name column takes the remainder.
@@ -2994,6 +3061,8 @@ export function ProfilesDataTable({
setContainerWidth(Math.round(w / 8) * 8);
setColumnVisibility((prev) => {
const next: VisibilityState = {
+ // Always hidden — sort-only column (issue #454).
+ created_at: false,
dns: w >= 768,
ext: w >= 672,
note: w >= 576,
diff --git a/src/components/profile-info-dialog.tsx b/src/components/profile-info-dialog.tsx
index 9bebda5..d756f19 100644
--- a/src/components/profile-info-dialog.tsx
+++ b/src/components/profile-info-dialog.tsx
@@ -878,6 +878,17 @@ function ProfileInfoLayout({
{t("profileInfo.sections.activity")}
+