Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/dashboard-content-card-hidden-collections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@emdash-cms/admin": patch
---

Fixes the dashboard's Content card listing collections that are hidden from navigation. The card now matches the sidebar and the quick actions; hidden collections still count toward the dashboard totals, still appear in Recent Activity, and stay reachable by URL, API, and plugins.
8 changes: 4 additions & 4 deletions docs/src/content/docs/concepts/collections.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ Collection settings control how editors and public pages use the entries:
- **Comments** can be enabled per collection, with moderation and automatic closing settings.
- **Icon** names the Phosphor icon shown next to the collection in the sidebar and command
palette, such as `calendar-blank`; a name that does not resolve falls back to the default icon.
- **Hide from navigation** removes the sidebar entry, the command palette link, and the dashboard
quick action while the collection stays reachable by URL, API, and plugins. Turning off **Quick action on the
dashboard** removes only the quick action, for collections that plugins or imports fill rather
than editors.
- **Hide from navigation** removes the sidebar entry, the command palette link, the dashboard quick
action, and the dashboard **Content** card row while the collection stays reachable by URL, API,
and plugins. Turning off **Quick action on the dashboard** removes only the quick action, for
collections that plugins or imports fill rather than editors.
- **Group** places the collection in a collapsible sidebar folder. Collections with the same group
share one folder, positioned where the first of them would appear. A taxonomy joins the folder when
every collection it is assigned to is shown in that folder.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/themes/seed-files.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ A collection requires `slug`, `label`, and `fields`:
| `supports` | `string[]` | Any of `drafts`, `revisions`, `preview`, `scheduling`, `search`, and `seo` |
| `urlPattern` | `string` | Public pattern such as `/posts/{slug}`, with at most one placeholder per path segment |
| `routable` | `boolean` | Whether published entries require a slug; defaults to `true` |
| `hidden` | `boolean` | Hides the generated sidebar link, command palette link, and dashboard quick action; the collection stays reachable by URL and API |
| `hidden` | `boolean` | Hides the generated sidebar link, command palette link, dashboard quick action, and dashboard **Content** card row; the collection stays reachable by URL and API |
| `sortOrder` | `number` | Explicit admin-sidebar position; ordered collections come first, ascending |
| `group` | `string` | Admin-sidebar folder; collections with the same group share one collapsible entry |
| `commentsEnabled` | `boolean` | Enables comments for the collection |
Expand Down
2 changes: 1 addition & 1 deletion packages/admin/src/components/ContentTypeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ export function ContentTypeEditor({
<div>
<span className="text-sm font-medium">{t`Hide from navigation`}</span>
<p className="text-xs text-kumo-subtle">
{t`Removes the sidebar entry, command palette link, and dashboard quick action; entries stay reachable by URL, API, and plugins`}
{t`Removes the sidebar entry, command palette link, dashboard quick action, and dashboard Content card row; entries stay reachable by URL, API, and plugins`}
</p>
</div>
}
Expand Down
5 changes: 3 additions & 2 deletions packages/admin/src/components/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -492,20 +492,21 @@ function CollectionList({
loading: boolean;
}) {
const { t } = useLingui();
const visibleCollections = collections.filter((col) => !manifest.collections[col.slug]?.hidden);

return (
<LayerCard className="h-full">
<DashboardCardHeading>{t`Content`}</DashboardCardHeading>
<LayerCard.Primary className="flex-1">
{loading ? (
<SkeletonRows count={3} />
) : collections.length === 0 ? (
) : visibleCollections.length === 0 ? (
<p className="px-3 text-sm leading-6 text-pretty text-kumo-subtle">
{t`No collections configured`}
</p>
) : (
<div className="space-y-1">
{collections.map((col) => {
{visibleCollections.map((col) => {
const config = manifest.collections[col.slug];
return (
<Link
Expand Down
2 changes: 1 addition & 1 deletion packages/admin/src/lib/api/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export interface SchemaCollection {
/** Published entries require a slug unless this is false. */
routable?: boolean;
hasSeo: boolean;
/** Sidebar entry and dashboard quick action omitted in the admin; the collection stays reachable by URL */
/** Sidebar entry, dashboard quick action, and dashboard Content card row omitted in the admin; the collection stays reachable by URL */
hidden: boolean;
/** Explicit sidebar position; absent means the alphabetical fallback */
sortOrder?: number;
Expand Down
29 changes: 29 additions & 0 deletions packages/admin/tests/components/Dashboard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,35 @@ describe("Dashboard", () => {
await expect.element(screen.getByRole("link", { name: "Setting" })).not.toBeInTheDocument();
});

it("omits hidden collections from the Content card", async () => {
mockFetchDashboardStats.mockResolvedValue(
makeStats([
{ slug: "pages", label: "Pages", total: 2, published: 1, draft: 1, scheduled: 0 },
{ slug: "sync_runs", label: "Sync runs", total: 5, published: 5, draft: 0, scheduled: 0 },
]),
);
const withHidden: AdminManifest = {
...manifest,
collections: {
...manifest.collections,
sync_runs: {
...manifest.collections.pages!,
label: "Sync runs",
labelSingular: "Sync run",
hidden: true,
},
},
};

const screen = await render(<Dashboard manifest={withHidden} />);

await expect
.element(screen.getByRole("link", { name: /^Pages/ }))
.toHaveAttribute("href", "/content/pages");
await expect.element(screen.getByRole("link", { name: /Sync runs/ })).not.toBeInTheDocument();
expect(screen.container.querySelector('a[href="/content/sync_runs"]')).toBeNull();
});

it("uses the same heading level for every dashboard card title", async () => {
mockFetchDashboardStats.mockResolvedValue(makeStats([]));

Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/astro/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ export interface ManifestCollection {
titleField?: string;
dateField?: string;
/**
* Omit the auto-generated sidebar entry and dashboard quick action in the
* admin. The collection is still listed in the manifest so its routes,
* editor, and API keep working.
* Omit the auto-generated sidebar entry, dashboard quick action, and
* dashboard Content card row in the admin. The collection is still listed
* in the manifest so its routes, editor, and API keep working.
*/
hidden?: boolean;
/** Phosphor icon name for the sidebar entry (kebab-case, e.g. `calendar-blank`). */
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/database/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ export interface CollectionTable {
date_field: string | null; // field slug (datetime) for the admin list Date column (NULL = default)
url_pattern: string | null; // URL pattern with {slug} placeholder (e.g. "/blog/{slug}")
routable: Generated<number>; // 0 or 1 — published entries require a slug when enabled
hidden: Generated<number>; // 0 or 1 — omit the auto-generated sidebar entry and dashboard quick action
hidden: Generated<number>; // 0 or 1 — omit the auto-generated sidebar entry, dashboard quick action, and dashboard Content card row
sort_order: number | null; // explicit admin sidebar position; NULL = alphabetical fallback
nav_group: string | null; // admin sidebar folder label; NULL = inline
comments_enabled: Generated<number>; // 0 or 1
Expand Down
13 changes: 7 additions & 6 deletions packages/core/src/schema/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,10 +282,11 @@ export interface Collection {
/** Whether published entries require a public slug. Defaults to true. */
routable?: boolean;
/**
* Omit this collection's auto-generated sidebar entry and dashboard quick
* action. The collection stays fully functional everywhere else (API, MCP,
* hooks, direct `/content/:collection` URLs), so a plugin that owns the
* collection can point editors at its own admin UI.
* Omit this collection's auto-generated sidebar entry, dashboard quick
* action, and dashboard Content card row. The collection stays fully
* functional everywhere else (API, MCP, hooks, direct `/content/:collection`
* URLs), so a plugin that owns the collection can point editors at its own
* admin UI.
*/
hidden: boolean;
/**
Expand Down Expand Up @@ -358,7 +359,7 @@ export interface CreateCollectionInput {
urlPattern?: string;
routable?: boolean;
hasSeo?: boolean;
/** Omit the auto-generated sidebar entry and dashboard quick action (defaults to false) */
/** Omit the auto-generated sidebar entry, dashboard quick action, and dashboard Content card row (defaults to false) */
hidden?: boolean;
/** Explicit admin sidebar position (omit for the alphabetical fallback) */
sortOrder?: number | null;
Expand All @@ -382,7 +383,7 @@ export interface UpdateCollectionInput {
urlPattern?: string | null;
routable?: boolean;
hasSeo?: boolean;
/** Omit the auto-generated sidebar entry and dashboard quick action */
/** Omit the auto-generated sidebar entry, dashboard quick action, and dashboard Content card row */
hidden?: boolean;
/** Explicit admin sidebar position; `null` clears it back to alphabetical */
sortOrder?: number | null;
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/seed/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ export interface SeedCollection {
/** Require a slug before an entry can be published. Defaults to true. */
routable?: boolean;
/**
* Omit this collection from the admin sidebar and the dashboard quick
* actions. It stays reachable through the API, MCP, plugin hooks, and
* direct `/content/:collection` URLs.
* Omit this collection from the admin sidebar, the dashboard quick
* actions, and the dashboard Content card. It stays reachable through the
* API, MCP, plugin hooks, and direct `/content/:collection` URLs.
*/
hidden?: boolean;
/**
Expand Down
Loading