Skip to content

[CSM Portal] SRA attachments, name display, project filtering, parentCase routing - #1283

Merged
Rashmika998 merged 5 commits into
wso2-open-operations:mainfrom
rksk:sra-optional-attachments
Jul 29, 2026
Merged

Rashmika998 merged 5 commits into
wso2-open-operations:mainfrom
rksk:sra-optional-attachments

Conversation

@rksk

@rksk rksk commented Jul 28, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc.

Follow-on fixes made after PR #1274 merged:

  1. Security Report Analysis (SRA) case creation bundled attachments into the same POST /cases request as the rest of the report, so a failed attachment upload sank the whole call — no case created, no navigation. The customer portal already fixed this exact pattern for its case-creation flow (PR fix(customer-portal): don't block case creation on attachment uploads #1254); CSM portal's other two create flows (CsmCaseCreatePage, CreateServiceRequestPage) already had it too, but SRA didn't.
  2. The case overview band showed fix-ETA fields that are being superseded by an upcoming Set/Share Fix ETA form redesign.
  3. Case creator and attachment uploader still showed raw emails on the FE despite an earlier fix adding createdByFullName to ServiceNow's response — entity-service was silently dropping the field before it ever reached the FE.
  4. The account detail page's Projects card always showed "Project list isn't available for the ServiceNow data source yet." — a client-side scan-and-filter workaround for a missing server-side accountId filter.
  5. parentCase on the case detail page assumed every parent was another case; ServiceNow's parentId can point at a case, incident, change request, or problem (digiops-cs#2568).

Goals

Describe the solutions that this feature/fix will introduce to resolve the problems described above

  1. Apply the decoupled create-then-upload pattern to SRA creation.
  2. Remove the fix-ETA fields from the case overview band.
  3. Fix creator/uploader name display end to end.
  4. Add a real server-side accountId filter to project search.
  5. Add a type discriminator to parentCase so the FE can route to the correct page for any parent type.

Approach

Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.

  1. SRA attachments: ServiceNow never actually required attachments for SRA creation (empirically confirmed — attachments: [] already succeeded); the "at least one attachment" rejection was purely an over-restrictive assumption in entity-service's own Go validation. Removed it (case_service.go), added a test asserting a zero-attachment request succeeds. CreateSecurityReportPage.tsx now creates the case first via postCase.mutateAsync (no attachments in the payload), then uploads any selected files afterward via uploadAttachmentsToCase with a non-blocking warning on partial failure and unconditional navigation to the created report.
  2. CaseMetaBand.tsx: removed the best/most-likely/worst-case fix-ETA cells and the now-unused formatDateOnlyForDisplay import.
  3. sn_case_service.go's wire structs (snCase, snAttachment) never had a CreatedByFullName field at all, so ServiceNow's already-fixed response data was silently dropped before reaching domain.CaseView.CreatedByDetails/domain.Attachment. Added the field to both, threaded through to the domain types the FE mappers already knew how to prefer (useGetCsmCaseDetail.ts, uiAttachmentFromBe).
  4. Added filters.accountId to ServiceNow's ProjectUtils.searchProjects (both the query and the cache key), domain.SearchProjectsRequest.AccountID in entity-service (UUID-validated, converted to sysid), and rewrote useAccountProjects.ts to send the filter directly instead of scanning + filtering the whole project catalogue client-side. Also fixed a real shape bug found along the way: BeProject/Project declared a flat accountId?: string that never matched the wire (entity-service returns a nested account: {id, name} object) — fixed both types to the real shape.
  5. ServiceNow: new CaseUtils._parentTypeLabel helper mapping a parent's sys_class_name (sn_customerservice_case/incident/change_request/problem) to a domain string, added to _mapCaseDetails's parentCase. Threaded through domain.CaseNumberRef.Type in entity-service and BeCaseNumberRef.type/CsmCaseDetail.parentCase.type on the FE. CsmCaseDetailPage.tsx's "Parent: …" chip now routes via a new parentCasePath() helper instead of always assuming /cases/{id}.

User stories

Summary of user stories addressed by this change

  • As a CS engineer creating a security report, if my attachment upload fails I still want the report to exist and land on its page.
  • As a CS engineer, I want to see who actually created a case or uploaded an attachment, not their raw email.
  • As a CS engineer viewing an account, I want its actual project list, not a permanent "not available" message.
  • As a CS engineer viewing a case linked to an incident/change request/problem as its parent, clicking the parent chip should take me to that record, not a broken case page.

Release note

Brief description of the new feature or bug fix as it will appear in the release notes

  • Security report creation no longer fails outright when an attachment upload has a problem.
  • Removed fix-ETA fields from the case overview band.
  • Case creator and attachment uploader now show the person's name instead of their raw email.
  • Account pages' Projects card now shows real, server-filtered results instead of a permanent "not available" message.
  • The case detail page's "Parent: …" chip now correctly routes to incidents/change requests/problems, not just cases.

Documentation

N/A — internal CSM portal UI/workflow changes, no external-facing documentation to update.

Training

N/A — no training content covers this internal portal.

Certification

N/A — no certification exam covers this internal portal.

Marketing

N/A — internal tooling change, not customer/market facing.

Automation tests

  • Unit tests

    go test ./..., go vet ./..., go build ./... clean on entity-service (added TestSNCaseService_CreateCase_SecurityReportAnalysis_AttachmentsOptional, TestSNProjectService_SearchProjects_MapsAccountRef and related coverage). npx tsc --noEmit, pnpm lint, and the relevant pnpm test suites clean on the webapp (rewrote useAccountProjects.test.tsx for the new server-side-filtered behavior).

  • Integration tests

    N/A — no integration test harness exercises these pages' DOM; verified end-to-end against a local stack pointed at the real ServiceNow DEV tenant (wso2sndev).

Security checks

  • Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? yes
  • Ran FindSecurityBugs plugin and verified report? N/A (Go/TypeScript project; ran go vet and eslint clean on the changed files instead)
  • Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? yes

Samples

N/A

Related PRs

Follow-on to #1274 (merged) — same phase-1/ServiceNow-vertical base branch (main).

Migrations (if applicable)

N/A — no schema or data migration involved.

Test environment

Verified with go build ./..., go test ./..., go vet ./... (entity-service), pnpm build, pnpm lint, npx tsc --noEmit (webapp), all on macOS/Node/Go local dev environment. End-to-end verified against a local stack (real Asgardeo + real ServiceNow DEV tenant).

Learning

N/A — implementation followed existing patterns already established in this codebase.

Summary by CodeRabbit

  • New Features
    • Projects can now be filtered by account using server-side search.
    • Parent case navigation uses the correct record type.
    • Security report creation supports optional attachments; files upload after creation.
    • Attachments can show the uploader’s name (with name/email fallback when available).
  • Bug Fixes
    • Removed outdated “filter unsupported” messaging; project lists now reflect correct empty/error states.
    • Improved messaging when attachment uploads partially fail.
    • Case metadata no longer shows fix-ETA fields where they don’t apply.

Security Report Analysis creation bundled attachments into the same POST
/cases request as everything else about the report, so a failed attachment
upload sank the whole call -- no case created, no navigation, the same
false-negative bug the customer portal already fixed for its case-creation
flow (PR wso2-open-operations#1254). This looked backend-mandated (entity-service rejected a
zero-attachment SRA request), but live-verified against wso2sndev: ServiceNow
itself never required attachments for SRA creation -- that was purely an
over-restrictive assumption in entity-service's own Go validation, mirrored
by a corresponding ServiceNow change removing 'attachments' from SRA's
required fields on Create Case (needed because entity-service's omitempty
tag drops the attachments key entirely when there are none, which SN's
required-fields check does reject).

- entity-service: dropped the 'at least one attachment' rejection for
  security_report_analysis; added a test asserting a zero-attachment
  request succeeds with no attachments key in the outbound payload.
- CreateSecurityReportPage.tsx: now creates the case first, uploads
  attachments afterward via uploadAttachmentsToCase (same pattern already
  used by CsmCaseCreatePage/CreateServiceRequestPage), with a non-blocking
  warning on partial upload failure and unconditional navigation to the
  created report.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: bfc59376-bf9b-4b83-b905-935a6d7903f6

📥 Commits

Reviewing files that changed from the base of the PR and between 340297a and 7fad08a.

📒 Files selected for processing (7)
  • apps/csm-portal/webapp/src/api/backend/mappers.ts
  • apps/csm-portal/webapp/src/api/backend/types.ts
  • apps/csm-portal/webapp/src/components/attachments/AttachmentsField.tsx
  • apps/csm-portal/webapp/src/features/csm-security-center/pages/CreateSecurityReportPage.tsx
  • entity-service/internal/domain/entity.go
  • entity-service/internal/service/sn_case_service.go
  • entity-service/openapi.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/csm-portal/webapp/src/features/csm-security-center/pages/CreateSecurityReportPage.tsx
  • entity-service/internal/service/sn_case_service.go
  • entity-service/internal/domain/entity.go

📝 Walkthrough

Walkthrough

The changes add ServiceNow account-filtered project searches, enrich case and attachment metadata, route parent-case links by type, support public Fix ETA updates, remove ETA cells from the case metadata band, and move security report attachments to a post-creation upload flow.

Changes

Project account filtering

Layer / File(s) Summary
Project account contracts
apps/csm-portal/webapp/src/api/backend/types.ts, apps/csm-portal/webapp/src/features/csm-projects/types/csmProjects.ts, entity-service/internal/domain/entity.go
Project models now expose account objects, and project search requests accept an accountId filter.
Server-side project filtering
entity-service/internal/service/sn_project_service.go, apps/csm-portal/webapp/src/features/csm-accounts/api/useAccountProjects.ts
The ServiceNow service converts account UUIDs to sysids, while the hook sends one filtered search request and only runs when an account id exists.
Account project rendering and tests
apps/csm-portal/webapp/src/features/csm-accounts/api/useAccountProjects.test.tsx, apps/csm-portal/webapp/src/features/csm-accounts/pages/CsmAccountDetailPage.tsx
Tests cover filtered requests, empty results, and disabled fetching; the page removes the unsupported-filter state.

Case metadata and update contracts

Layer / File(s) Summary
Case and attachment response enrichment
entity-service/internal/domain/entity.go, entity-service/internal/service/sn_case_service.go, entity-service/openapi.yaml, apps/csm-portal/webapp/src/api/backend/..., apps/csm-portal/webapp/src/features/csm-cases/...
Parent-case types and uploader display names are added to backend contracts, mapped through ServiceNow responses, and exposed in frontend models.
Public Fix ETA update payload
entity-service/internal/domain/entity.go, entity-service/internal/service/sn_case_service.go
Case updates accept addPublicComment, product, and publicTicket, with validation before forwarding the values.
Parent routing and metadata display
apps/csm-portal/webapp/src/features/csm-cases/pages/CsmCaseDetailPage.tsx, apps/csm-portal/webapp/src/features/csm-cases/components/CaseMetaBand.tsx
Parent links use type-specific routes, and the three ETA cells are removed from the metadata band.

Security report attachment workflow

Layer / File(s) Summary
Optional security report attachments
entity-service/internal/domain/entity.go, entity-service/internal/service/case_service.go, entity-service/internal/service/sn_case_service_create_test.go
Security report creation permits no attachments while continuing to validate supplied files, with coverage for the empty-attachment request.
Create then upload workflow
apps/csm-portal/webapp/src/features/csm-security-center/pages/CreateSecurityReportPage.tsx, apps/csm-portal/webapp/src/components/attachments/AttachmentsField.tsx, apps/csm-portal/webapp/src/features/csm-cases/api/uploadAttachmentsToCase.ts
The page creates the report first and uploads attachments afterward, using the encoded-byte limit, submission state, disabled controls, and partial-failure handling.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CreateSecurityReportPage
  participant CaseAPI
  participant AttachmentAPI
  User->>CreateSecurityReportPage: submit report
  CreateSecurityReportPage->>CaseAPI: create security report
  CaseAPI-->>CreateSecurityReportPage: return case id
  CreateSecurityReportPage->>AttachmentAPI: upload attachments for case
  AttachmentAPI-->>CreateSecurityReportPage: return upload results
  CreateSecurityReportPage-->>User: show result and navigate to case
Loading

Possibly related PRs

Suggested labels: Type/Improvement, Area/Backend

Suggested reviewers: rashmika998, cloby99

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the PR’s main themes: SRA attachments, creator name display, project filtering, and parent-case routing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

rksk added 3 commits July 28, 2026 23:07
Being replaced by the Set/Share Fix ETA form redesign; the overview band
isn't the right place to surface these values.
…er-side account-project filter

Case creator and attachment uploader still showed raw emails on the FE
despite the earlier SN fix adding createdByFullName -- entity-service never
actually wired the field through: snCase and snAttachment (the case-detail
and attachment-search wire structs) never had a CreatedByFullName field at
all, so it was silently dropped before reaching the FE. Added the missing
field to both wire structs and threaded it into domain.CaseView.CreatedByDetails
and domain.Attachment; the FE case-detail mapper already preferred name over
email (useGetCsmCaseDetail.ts) so it now picks it up automatically, and
uiAttachmentFromBe now does the same for attachments.

Also: POST /projects/search gained a real server-side accountId filter
(ServiceNow: new addQuery('account', ...) in ProjectUtils, cache key updated
to include it; entity-service: new AccountID field threaded through with
UUID validation). Rewrote useAccountProjects.ts to use this instead of
scanning + client-side filtering the whole project catalogue, removing the
isFilterSupported workaround and its 'not available' message entirely.
Fixed a related shape bug: entity-service returns the account reference as
a nested account: {id, name} object, but the FE's Project/BeProject types
declared a flat accountId string that never matched the wire -- so the
account filter could never have worked even after the field was added.
Updated both types and the account-detail page's ProjectsSection.
…for non-case parents

digiops-cs#2568 (parentCase null for an incident parent) was already fixed
by an earlier session-2 change: _mapCaseDetails previously never set
parentCase on GET /cases/{id} at all (only the list view and the immediate
PATCH response did). Live-verified fresh against a real case-to-incident
link that this already works end to end.

This adds the follow-up the issue also flagged: parentCase now carries a
type (case/incident/change_request/problem, resolved from the parent
record's actual sys_class_name on the ServiceNow side), threaded through
entity-service (CaseNumberRef.Type) and the FE. The case detail page's
'Parent: ...' chip previously assumed every parent was a case and always
navigated to /cases/{id} -- now routes to the correct section for an
incident/change-request/problem parent.
@rksk rksk changed the title [CSM Portal] decouple SRA attachment upload from case creation [CSM Portal] SRA attachments, name display, project filtering, parentCase routing Jul 29, 2026
@rksk
rksk marked this pull request as ready for review July 29, 2026 06:39
@rksk

rksk commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
apps/csm-portal/webapp/src/features/csm-accounts/api/useAccountProjects.ts (1)

29-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider surfacing total/hasMore so truncation is visible.

The comment acknowledges results are silently capped at BE_MAX_PAGE_LIMIT, but the hook discards total/hasMore from the response, so the Projects section can't even hint that rows are missing. Returning them lets the table show a "showing first N of M" note until a pager exists.

♻️ Proposed change
-): UseQueryResult<{ projects: Project[] }, Error> {
+): UseQueryResult<{ projects: Project[]; total: number; hasMore: boolean }, Error> {

and return { projects: data.projects ?? [], total: data.total ?? 0, hasMore: data.hasMore ?? false }.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/csm-portal/webapp/src/features/csm-accounts/api/useAccountProjects.ts`
around lines 29 - 40, Update useAccountProjects to preserve and expose the
response metadata alongside the projects array: return projects with total and
hasMore, defaulting missing values to an empty array, zero, and false
respectively. Update the hook’s UseQueryResult type so consumers can access all
three fields, while keeping the existing account filtering and page limit
behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/csm-portal/webapp/src/api/backend/mappers.ts`:
- Line 212: Update the uploader-name expression in the attachment mapper so the
createdBy fallback is trimmed before applying the "Unknown" default; preserve
the existing priority of createdByFullName, then the cleaned createdBy
identifier, then "Unknown".

In
`@apps/csm-portal/webapp/src/features/csm-security-center/pages/CreateSecurityReportPage.tsx`:
- Around line 321-338: Update the AttachmentsField usage in
CreateSecurityReportPage so attachment additions and removals are disabled
whenever submitting is true, matching the locked editor state and preserving the
handleSubmit attachment snapshot.

In `@entity-service/internal/domain/entity.go`:
- Around line 1619-1630: Change Attachment.CreatedByFullName from string to
*string and update SearchCaseAttachments to trim the source name, assign a
pointer only when non-empty, and leave it nil when unresolved. Preserve the
existing frontend fallback behavior and update any affected mappings or type
usages to handle the nullable field.
- Around line 978-982: The CaseNumberRef.Type value is passed through without
mapping and can expose unsupported ServiceNow task types. Add a shared domain
enum/mapper for parent-case task types that maps only case, incident,
change_request, and problem values and returns nil for unknown values; update
GetCaseByID to use it instead of assigning c.ParentCase.Type directly, and align
the ServiceNow and OpenAPI CaseNumberRef.type definitions with the mapped
response.

In `@entity-service/internal/service/sn_case_service.go`:
- Around line 139-141: Update the UpdateCase response builder to populate
snCaseRef.Type from the updated parent record, matching the existing GetCaseByID
mapping. Apply the same Type propagation to the corresponding response
construction at the other referenced location, preserving the discriminator for
incident, change request, and problem parent links.

---

Nitpick comments:
In `@apps/csm-portal/webapp/src/features/csm-accounts/api/useAccountProjects.ts`:
- Around line 29-40: Update useAccountProjects to preserve and expose the
response metadata alongside the projects array: return projects with total and
hasMore, defaulting missing values to an empty array, zero, and false
respectively. Update the hook’s UseQueryResult type so consumers can access all
three fields, while keeping the existing account filtering and page limit
behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4579eb4f-d373-4bc2-b1b4-1329981f4346

📥 Commits

Reviewing files that changed from the base of the PR and between 262963d and 340297a.

📒 Files selected for processing (17)
  • apps/csm-portal/webapp/src/api/backend/mappers.ts
  • apps/csm-portal/webapp/src/api/backend/types.ts
  • apps/csm-portal/webapp/src/features/csm-accounts/api/useAccountProjects.test.tsx
  • apps/csm-portal/webapp/src/features/csm-accounts/api/useAccountProjects.ts
  • apps/csm-portal/webapp/src/features/csm-accounts/pages/CsmAccountDetailPage.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/api/uploadAttachmentsToCase.ts
  • apps/csm-portal/webapp/src/features/csm-cases/api/useGetCsmCaseDetail.ts
  • apps/csm-portal/webapp/src/features/csm-cases/components/CaseMetaBand.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/pages/CsmCaseDetailPage.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/types/csmCases.ts
  • apps/csm-portal/webapp/src/features/csm-projects/types/csmProjects.ts
  • apps/csm-portal/webapp/src/features/csm-security-center/pages/CreateSecurityReportPage.tsx
  • entity-service/internal/domain/entity.go
  • entity-service/internal/service/case_service.go
  • entity-service/internal/service/sn_case_service.go
  • entity-service/internal/service/sn_case_service_create_test.go
  • entity-service/internal/service/sn_project_service.go
💤 Files with no reviewable changes (1)
  • apps/csm-portal/webapp/src/features/csm-cases/components/CaseMetaBand.tsx

Comment thread apps/csm-portal/webapp/src/api/backend/mappers.ts Outdated
Comment thread entity-service/internal/domain/entity.go
Comment thread entity-service/internal/domain/entity.go Outdated
Comment thread entity-service/internal/service/sn_case_service.go
…parent-case type

- Attachment.createdBy is now a UserRef object ({id, name, email}), matching
  the convention case createdBy already uses, instead of two flat
  createdBy/createdByFullName strings.
- Map ServiceNow's raw parent-case type value (e.g. "default_case") to the
  public case/incident/change_request/problem enum instead of passing it
  through unmapped, and propagate it on UpdateCase responses too, not just
  GetCaseByID.
- Disable AttachmentsField's add/remove controls while a security report
  create is submitting, so the attachment list can't drift from the
  snapshot handleSubmit uploads.
@rksk

rksk commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants