feat: integration/webhook counts in project overview

ProjectOverview gains integration_count + webhook_count (enabled only);
dashboard Resources list gets an Integrations row linking to the new
view. Covers the "dashboard widget if cheap" Phase 4 item.

Authored By: TDvorak <[email protected]>
This commit is contained in:
Tomas Dvorak committed 2026-09-16 19:18:15 +02:00
1 parent e25eb92339
commit 23186e38b8
8 files changed
+71 -2

No files matched your search

+12 -1
View File
@@ -136,7 +136,18 @@ SELECT
SELECT MAX(al.created_at)::TIMESTAMPTZ
FROM core.audit_logs al
WHERE al.project_id = p.id
) AS last_audit_at
) AS last_audit_at,
(
SELECT COUNT(*)::BIGINT
FROM core.integrations i
WHERE i.project_id = p.id
) AS integration_count,
(
SELECT COUNT(*)::BIGINT
FROM core.webhooks w
WHERE w.project_id = p.id
AND w.enabled
) AS webhook_count
FROM core.projects p
WHERE p.id = $1;
@@ -217,7 +217,18 @@ SELECT
SELECT MAX(al.created_at)::TIMESTAMPTZ
FROM core.audit_logs al
WHERE al.project_id = p.id
) AS last_audit_at
) AS last_audit_at,
(
SELECT COUNT(*)::BIGINT
FROM core.integrations i
WHERE i.project_id = p.id
) AS integration_count,
(
SELECT COUNT(*)::BIGINT
FROM core.webhooks w
WHERE w.project_id = p.id
AND w.enabled
) AS webhook_count
FROM core.projects p
WHERE p.id = $1
`
@@ -235,6 +246,8 @@ type GetProjectOverviewRow struct {
PendingInvitationCount int64 `json:"pending_invitation_count"`
AuditEvents24h int64 `json:"audit_events_24h"`
LastAuditAt pgtype.Timestamptz `json:"last_audit_at"`
IntegrationCount int64 `json:"integration_count"`
WebhookCount int64 `json:"webhook_count"`
}
func (q *Queries) GetProjectOverview(ctx context.Context, id uuid.UUID) (GetProjectOverviewRow, error) {
@@ -253,6 +266,8 @@ func (q *Queries) GetProjectOverview(ctx context.Context, id uuid.UUID) (GetProj
&i.PendingInvitationCount,
&i.AuditEvents24h,
&i.LastAuditAt,
&i.IntegrationCount,
&i.WebhookCount,
)
return i, err
}
@@ -179,6 +179,8 @@ type ProjectOverview struct {
PendingInvitationCount int64 `json:"pending_invitation_count"`
AuditEvents24h int64 `json:"audit_events_24h"`
LastAuditAt *time.Time `json:"last_audit_at,omitempty"`
IntegrationCount int64 `json:"integration_count"`
WebhookCount int64 `json:"webhook_count"`
}
type OrganizationMemberSummary struct {
@@ -586,6 +588,8 @@ func (s *PlatformService) GetProjectOverview(ctx context.Context, actor *models.
PendingInvitationCount: row.PendingInvitationCount,
AuditEvents24h: row.AuditEvents24h,
LastAuditAt: projectOverviewLastAuditAt(row.LastAuditAt),
IntegrationCount: row.IntegrationCount,
WebhookCount: row.WebhookCount,
}, nil
}
+10
View File
@@ -1979,6 +1979,14 @@ components:
type: string
format: date-time
nullable: true
integration_count:
type: integer
format: int64
description: Connectors attached to the project.
webhook_count:
type: integer
format: int64
description: Enabled outbound webhooks.
required:
- project_id
- organization_id
@@ -1991,6 +1999,8 @@ components:
- object_bytes_total
- pending_invitation_count
- audit_events_24h
- integration_count
- webhook_count
ProjectMember:
type: object
properties:
@@ -6,6 +6,7 @@ import {
IconMembers,
IconAudit,
IconCollections,
IconIntegrations,
IconChevronRight,
} from "./Icons";
@@ -110,6 +111,12 @@ export function ProjectDashboard(props: ProjectDashboardProps) {
icon: IconMembers,
view: "members",
},
{
title: "Integrations",
sub: `${overview()?.integration_count ?? 0} connectors · ${overview()?.webhook_count ?? 0} webhooks`,
icon: IconIntegrations,
view: "integrations",
},
];
const audit = () => (props.recentAudit ?? []).slice(0, 6);
+2
View File
@@ -511,6 +511,8 @@ class DemoService {
pending_invitation_count: invitations.filter((i) => i.status === OrganizationInvitation.status.PENDING).length,
audit_events_24h: auditLogs.length,
last_audit_at: auditLogs[0]?.created_at ?? null,
integration_count: demoIntegrations.length,
webhook_count: demoWebhooks.filter((w) => w.enabled).length,
};
}