Show when each extension was last updated

MCP, skill and tool rows in Settings say "Updated 5m ago" beside how
they're reached and who gets them. updated_at now means a change to an
extension's settings (an edit, or any Access save): runs, connections and
MCP syncs keep their own last_checked_at / last_synced_at and no longer
touch it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-26 08:07:44 +01:00
co-authored by Claude Opus 5.5
parent b9008b22cb
commit 2df1bf83f4
18 changed files with 62 additions and 16 deletions
@@ -0,0 +1,13 @@
import checkedAgo from "./checked-ago";
type Params = {
at: number | null;
};
/**
* When an extension's settings last changed, for a row's subtitle:
* "Updated 5m ago". Nothing when it's never been stamped.
*/
export default function updatedAgo({ at }: Params) {
return at ? `Updated ${checkedAgo({ at })}` : undefined;
}
@@ -11,6 +11,7 @@ import SettingsListRow from "../../(partials)/settings-list-row";
import SettingsRowAction from "../../(partials)/settings-row-action";
import checkedAgo from "../../(utils)/checked-ago";
import extensionAccessLabel from "../../(utils)/extension-access-label";
import updatedAgo from "../../(utils)/updated-ago";
import McpServerModal from "./mcp-server-modal";
type Props = {
@@ -63,6 +64,7 @@ export default function McpServerRow({ server, targets, onChanged, onError }: Pr
subtitle={[
McpTransports.find((t) => t.value == server.transport)?.title,
extensionAccessLabel({ access: server.access }),
updatedAgo({ at: server.updated_at }),
]
.filter(Boolean)
.join(" · ")}
@@ -8,6 +8,7 @@ import ExtensionAccessModal from "../../(partials)/extension-access-modal";
import SettingsListRow from "../../(partials)/settings-list-row";
import SettingsRowAction from "../../(partials)/settings-row-action";
import extensionAccessLabel from "../../(utils)/extension-access-label";
import updatedAgo from "../../(utils)/updated-ago";
import SkillModal from "./skill-modal";
type Props = {
@@ -51,7 +52,12 @@ export default function SkillRow({ skill, targets, limits, onChanged, onError }:
avatar={<IconTile Icon={BookOpen} />}
title={skill.name}
badge={skill.enabled ? undefined : "Off"}
subtitle={[skill.slug, extensionAccessLabel({ access: skill.access }), skill.description]
subtitle={[
skill.slug,
extensionAccessLabel({ access: skill.access }),
updatedAgo({ at: skill.updated_at }),
skill.description,
]
.filter(Boolean)
.join(" · ")}
>
@@ -11,6 +11,7 @@ import SettingsListRow from "../../(partials)/settings-list-row";
import SettingsRowAction from "../../(partials)/settings-row-action";
import checkedAgo from "../../(utils)/checked-ago";
import extensionAccessLabel from "../../(utils)/extension-access-label";
import updatedAgo from "../../(utils)/updated-ago";
import CustomToolModal from "./custom-tool-modal";
import CustomToolTryModal from "./custom-tool-try-modal";
@@ -72,6 +73,7 @@ export default function CustomToolRow({ tool, targets, onChanged, onRefreshed, o
subtitle={[
CustomToolKinds.find((k) => k.value == tool.kind)?.title,
extensionAccessLabel({ access: tool.access }),
updatedAgo({ at: tool.updated_at }),
tool.description,
]
.filter(Boolean)