Add project count to security scan profiles
What does this MR do and why?
Exposes how many projects each security scan profile is attached to, and surfaces the count in two places under the group Security Configuration → Manage profiles drawer: next to the managed-by chip on each list card, and as a muted second line on the delete confirmation modal (N projects currently use this profile and will be left without one.). Also fixes a small Esc-handling bug in the delete flow noticed while wiring the count in.
ScanProfileType grows a projectCount field (experiment: { milestone: '19.5' }) backed by a BatchLoader::GraphQL over Security::ScanProfile.project_counts_by_id, so listing profiles stays a single SELECT ... GROUP BY security_scan_profile_id. The class method lives on the owning ScanProfile next to scan_type_names_for_project, matching the codebase convention for cross-cutting ScanProfile queries. Frontend adds projectCount to the ScanProfileFields fragment, an icon + number to scan_profile_list.vue (with a visually-hidden pluralized label for screen readers), and a pluralized n__ line to the delete modal (rendered only when projectCount > 0). The Esc fix intercepts GlDrawer's close when a delete modal is pending, so Esc closes only the modal, not both, and clears the pending state whenever the drawer reopens.
References
- issue: [Frontend] Scan profile drawer: view, create, e... (#624191 - closed)
- parent work item: Advanced Configuration Profiles for Security Sc... (gitlab-org#20193)
- Design:
security-inventory-profiles
Screenshots or screen recordings
| Before | After |
|---|---|
Query plans
Raw SQL
SELECT
COUNT(*),
security_scan_profile_id
FROM
security_scan_profiles_projects
WHERE
security_scan_profile_id IN (1049, 1002412, 1004782, 974)
GROUP BY
security_scan_profile_id;
Plan
See details here.
GroupAggregate (cost=0.29..13.17 rows=26 width=16) (actual time=3.246..8.257 rows=3 loops=1)
Group Key: security_scan_profiles_projects.security_scan_profile_id
Buffers: shared hit=3 read=7 dirtied=2
WAL: records=4 fpi=2 bytes=16594
I/O Timings: read=5.848 write=0.000
-> Index Only Scan using idx_security_scan_profiles_projects_on_security_scan_profile_id on public.security_scan_profiles_projects (cost=0.29..12.78 rows=26 width=8) (actual time=1.783..8.225 rows=25 loops=1)
Index Cond: (security_scan_profiles_projects.security_scan_profile_id = ANY ('{1049,1002412,1004782,974}'::bigint[]))
Heap Fetches: 8
Index Searches: 3
Buffers: shared hit=3 read=7 dirtied=2
WAL: records=4 fpi=2 bytes=16594
I/O Timings: read=5.848 write=0.000
Settings: random_page_cost = '1.5', seq_page_cost = '4', effective_cache_size = '338688MB', jit = 'off', work_mem = '100MB'
Query ID: 1092854818462895081How to set up and validate locally
- Enable the feature flag on a Rails console:
Feature.enable(:custom_secret_detection_profiles_ui). - Seed at least one Custom Secret Detection profile in the target group and attach it to two projects (via GraphQL
securityScanProfileAttachorSecurity::ScanProfileProject.create!). - Open the group's Security Configuration page and click Manage profiles on the Secret Detection row. Each card in the list now shows the attached-project count next to the GitLab/Custom chip.
- Select the custom profile with two attached projects, then click the trash icon in the detail header. The modal shows a muted second line reading
2 projects currently use this profile and will be left without one.. - Detach a project so the profile has one left, and reopen the delete modal. The line now reads
1 project currently uses this profile and will be left without one.(singular). - Detach all projects. Reopen the modal. The extra line is hidden.
- Esc guard: open the modal, press Esc. Only the modal closes, the drawer stays open. Close the modal via Cancel, then press Esc again. Now the drawer closes.
- No stale pending state: open the modal, close the drawer via Esc (with modal open, then Esc twice). Reopen the drawer with Manage profiles. The delete modal is not visible.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.


