Skip to content

Conversation

@Sudeep7353
Copy link
Contributor

@Sudeep7353 Sudeep7353 commented Jan 7, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added MISP license key expiry notification tracking and management
    • Enabled API key expiry date editing
    • Expanded OIDC client configuration with multi-language name support
    • Added consent duration, sign-up/password banners, and purpose type configuration for OIDC clients
    • Introduced ABIS partner type support
    • Enhanced notification filters for MISP license key expiry events
  • Improvements

    • Extended multi-language support across configuration interfaces
    • Improved certificate management for multiple partner types

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 7, 2026

Walkthrough

This PR introduces MISP license key expiry notifications, expands OIDC client capabilities with multilingual names and additional configuration options, adds API key expiry editing, implements ABIS partner support, migrates session storage from localStorage to sessionStorage across components, updates deployment versions, and adds comprehensive i18n translations for all new features.

Changes

Cohort / File(s) Summary
Version & Deployment Updates
README.md, helm/pmp-ui-v2/Chart.yaml, deploy/pmp-ui-v2/install.sh, deploy/uitest-pmp-v2/install.sh
Removed beta tags from chart versions (1.3.0-beta.3-develop → 1.3.0-develop) and updated deployment references.
Container Image Configuration
helm/pmp-ui-v2/values.yaml, deploy/uitest-pmp-v2/values.yaml
Updated image repositories from mosipid/ to mosipqa/ and adjusted image tags (1.3.0-beta.3 → 1.3.x and 1.3.4 → 1.3.0-develop).
Internationalization (i18n) Translations
pmp-ui-v2/public/i18n/ara.json, pmp-ui-v2/public/i18n/eng.json, pmp-ui-v2/public/i18n/fra.json
Added 144+ new translation keys across Arabic, English, and French for MISP license expiry, OIDC client multilingual support, consent management, purpose/title/subtitle fields, and expiry date editing workflows.
Storage Migration (localStorage → sessionStorage)
pmp-ui-v2/src/nav/HeaderNav.js, pmp-ui-v2/src/nav/MainLayout.js, pmp-ui-v2/src/pages/admin/authenticationServices/AdminApiKeysList.js, pmp-ui-v2/src/pages/admin/authenticationServices/ViewAdminApiKeyDetails.js, pmp-ui-v2/src/pages/admin/certificates/TrustList.js, pmp-ui-v2/src/pages/admin/certificates/UploadTrustCertificate.js, pmp-ui-v2/src/pages/admin/certificates/ViewTrustDetails.js, pmp-ui-v2/src/pages/admin/deviceProviderServices/*, pmp-ui-v2/src/pages/admin/ftmProviderServices/AdminFtmList.js, pmp-ui-v2/src/pages/admin/ftmProviderServices/ViewAdminFtmChipDetails.js, pmp-ui-v2/src/pages/admin/mispPartnerServices/MispLicenseList.js, pmp-ui-v2/src/pages/admin/mispPartnerServices/RegenerateMispLicenseKey.js, pmp-ui-v2/src/pages/admin/mispPartnerServices/ViewMispLicenseKey.js, pmp-ui-v2/src/pages/admin/partners/PartnersList.js, pmp-ui-v2/src/pages/admin/partners/ViewPartnerDetails.js, pmp-ui-v2/src/pages/admin/policyManager/*, pmp-ui-v2/src/pages/admin/policyRequests/*, pmp-ui-v2/src/pages/common/Pagination.js, pmp-ui-v2/src/pages/partner/authenticationServices/*, pmp-ui-v2/src/pages/partner/certificates/UploadCertificate.js, pmp-ui-v2/src/pages/partner/deviceProviderServices/*, pmp-ui-v2/src/pages/partner/ftmProviderServices/*, pmp-ui-v2/src/pages/partner/notifications/*, pmp-ui-v2/src/pages/partner/policies/*, pmp-ui-v2/src/services/ConfigService.js, pmp-ui-v2/src/services/HttpService.js
Systematically replaced localStorage with sessionStorage for persisting UI state (items per page, selected records, active tabs) and session-scoped data throughout the application, confining data lifetime to current browser session.
API Key Expiry Editing
pmp-ui-v2/src/pages/admin/authenticationServices/AdminApiKeysList.js, pmp-ui-v2/src/pages/admin/authenticationServices/EditAdminApiKey.js
Added new EditAdminApiKey component with date validation and PATCH request for API key expiry updates; enhanced AdminApiKeysList with "Edit Expiry Date" action button and updated deactivation status string to "De-active".
OIDC Client Details Refactoring
pmp-ui-v2/src/pages/admin/authenticationServices/ViewAdminOidcClientDetails.js, pmp-ui-v2/src/pages/partner/authenticationServices/ViewOidcClientDetails.js, pmp-ui-v2/src/pages/common/OidcClientDetailsPage.js
Replaced detailed view implementations with centralized OidcClientDetailsPage component that handles both admin and partner variants, simplifying code while maintaining feature parity.
OIDC Client Creation & Management
pmp-ui-v2/src/pages/partner/authenticationServices/CreateOidcClient.js, pmp-ui-v2/src/pages/partner/authenticationServices/EditOidcClient.js, pmp-ui-v2/src/pages/admin/authenticationServices/AdminOidcClientsList.js, pmp-ui-v2/src/pages/partner/authenticationServices/OidcClientsList.js
Expanded OIDC client forms with multilingual client names, additional information section (consent expiry, purpose types, title/subtitle mappings), and conditional deactivation logic based on additionalConfigRequired flag.
New OIDC Client Components
pmp-ui-v2/src/pages/common/OidcClientAdditionalInfoSection.js, pmp-ui-v2/src/pages/common/fields/TextInputComponentWithDeleteButton.js, pmp-ui-v2/src/pages/common/CalendarInput.js
Introduced new reusable components for OIDC client additional info (expandable panel with consent/purpose/banner toggles), multi-language text inputs with delete actions, and enhanced calendar input with keyboard accessibility.
MISP License Key Notifications
pmp-ui-v2/src/pages/admin/notifications/ViewMispLicenseKeyNotifications.js, pmp-ui-v2/src/pages/admin/notifications/ViewAllNotifications.js, pmp-ui-v2/src/pages/admin/notifications/AdminNotificationsTab.js, pmp-ui-v2/src/pages/partner/notifications/MispLicenseKeyNotificationFilter.js
Added new MISP license key expiry notification flow with dedicated view component, notification filter, and tab support in admin notifications interface.
Dashboard & Navigation Updates
pmp-ui-v2/src/pages/dashboard/Dashboard.js, pmp-ui-v2/src/pages/dashboard/SelectPolicyPopup.js, pmp-ui-v2/src/pages/dashboard/MissingAttributesPopup.js
Enhanced dashboard with MISP license key expiry count display, role-based data fetching guards, consent checks, and replaced partner type button with read-only text input; removed MissingAttributesPopup component.
Route & Authentication
pmp-ui-v2/src/AppRoutes.js, pmp-ui-v2/src/auth/GuardedRoute.js
Added routes for EditAdminApiKey and ViewMispLicenseKeyNotifications; updated route guards to derive admin/policy-manager roles from userProfile and switched storage to sessionStorage.
ABIS Partner Support
pmp-ui-v2/src/pages/admin/partners/CreatePartner.js, pmp-ui-v2/src/pages/admin/partners/PartnersList.js, pmp-ui-v2/src/pages/partner/policies/RequestPolicy.js, pmp-ui-v2/src/pages/common/DeactivatePopup.js
Added ABIS\_Partner type support alongside MISP\_Partner with dynamic certificate upload flags, partner-type-driven API endpoint selection, and conditional policy group requirements.
Utility & Service Updates
pmp-ui-v2/src/utils/AppUtils.js, pmp-ui-v2/src/services/HttpService.js
Implemented backend-driven partner type fetching, added 20+ new OIDC client utilities (dropdown initializers, language mapping, entry builders, validation), introduced fetchUserConsent, updated MISP notification handling, and expanded language/client-name helpers.
UI & Layout Refinements
pmp-ui-v2/src/pages/common/Confirmation.js, pmp-ui-v2/src/pages/common/CopyIdPopup.js, pmp-ui-v2/src/pages/common/PolicyGroupSelector.js, pmp-ui-v2/src/pages/common/fields/Information.js, pmp-ui-v2/src/pages/admin/mispPartnerServices/GenerateMispLicenseKey.js, pmp-ui-v2/tailwind.config.js
Updated button layouts for custom confirmation buttons, enhanced tooltips with RTL and extended responsive styles, added RTL-aware flex utilities, refined margins, and introduced max-800 responsive breakpoint.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested reviewers

  • mohanachandran-s

Poem

🐰 Hops through localStorage with a bound
SessionStorage keeps our data sound
MISP keys dance, OIDC names grow true
API dates flex, ABIS partners too
Multilingual magic, notifications flow—
Partner Management Portal's brand new glow!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective of the pull request: merging develop code into the release-1.3.x branch for version 1.3.0-beta.4. It is clear, specific, and directly related to the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

@Sudeep7353 Sudeep7353 force-pushed the mydev222-merge branch 2 times, most recently from 2adb5e8 to 22a27a8 Compare January 7, 2026 10:40
@mayuradesh mayuradesh changed the title MOSIP-43932: Merged develop code to release branch. MOSIP-43982: Merged develop code to release branch. Jan 9, 2026
@mayuradesh mayuradesh changed the title MOSIP-43982: Merged develop code to release branch. MOSIP-43982: Moving develop code to release branch for 1.3.0-beta.4 Jan 9, 2026
Copy link
Contributor

@mayuradesh mayuradesh left a comment

Choose a reason for hiding this comment

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

Retain ReadMe
Remove uitest-pmp-v2 automation team will add

@mayuradesh
Copy link
Contributor

@coderabbitai review this PR

@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

@mayuradesh: I'll review the changes in this PR for you.

✅ Actions performed

Review triggered.

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 19

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (10)
pmp-ui-v2/src/pages/admin/deviceProviderServices/AdminDevicesList.js (1)

266-273: Wrap sessionStorage.setItem in try-catch to prevent navigation blocking on quota exceeded

If storage is unavailable or quota exceeded, setItem can throw and prevent the details page from opening. The proposed fix is appropriate.

The secondary concern is already addressed—the details page (ViewAdminDeviceDetails.js line 21) correctly reads from sessionStorage, not localStorage.

Proposed change
-        sessionStorage.setItem('selectedDeviceAttributes', JSON.stringify(requiredData));
+        try {
+            sessionStorage.setItem('selectedDeviceAttributes', JSON.stringify(requiredData));
+        } catch (_) {
+            // best-effort persistence; still navigate
+        }
         navigate("/partnermanagement/admin/device-provider-services/view-device-details");
deploy/uitest-pmp-v2/install.sh (2)

33-45: Fix the “(Y/n)” prompt default + incorrect error message text.
Prompt says (Y/n) but empty input exits, and Line 39 message says “‘flag’ was provided” when it wasn’t. Consider defaulting empty to Y and accepting Y/y/N/n.

Proposed patch
-  read -p "" flag
+  read -r -p "Enter Y or n: " flag
+  flag="${flag:-Y}"

-  if [ -z "$flag" ]; then
-    echo "'flag' was provided; EXITING;"
-    exit 1;
-  fi
   ENABLE_INSECURE=''
-  if [ "$flag" = "n" ]; then
+  if [[ "${flag,,}" == "n" ]]; then
     ENABLE_INSECURE='--set uitestrig.configmaps.uitestrig.ENABLE_INSECURE=true';
   fi

5-15: Move strict mode to script top and make namespace creation idempotent; verify chart version in external Helm repo.

The kubectl create ns $NS on line 14 executes before set -e protection (line 92), so failures on reruns go unnoticed. The namespace creation also lacks idempotency—it will fail if the namespace already exists. Additionally, variables throughout the script are unquoted, risking word splitting.

The 1.3.0-develop chart version for mosip/uitestrig requires manual verification in the external Helm repo, as does the docker image tag for mosipqa/uitest-pmp-v2.

Proposed patch
 #!/bin/bash
 # Installs uitestrig automation
 ## Usage: ./install.sh [kubeconfig]

+set -euo pipefail
+
 if [ $# -ge 1 ] ; then
-  export KUBECONFIG=$1
+  export KUBECONFIG="$1"
 fi

 NS=pms
 CHART_VERSION=1.3.0-develop
 COPY_UTIL=../copy_cm_func.sh

 echo Create $NS namespace
-kubectl create ns $NS
+kubectl create ns "$NS" --dry-run=client -o yaml | kubectl apply -f -

To validate the external versions/tags, check locally:

  • helm repo update && helm search repo mosip/uitestrig --versions | grep 1.3.0-develop
  • Confirm docker tag exists: docker manifest inspect mosipqa/uitest-pmp-v2:1.3.x (or via docker registry API)
deploy/pmp-ui-v2/install.sh (1)

5-15: Add strict mode early, quote variables, and make namespace creation idempotent.

The script currently sets strict mode (lines 46–51) after initial operations, leaving early lines vulnerable to unhandled errors. Additionally, $1, $NS, and other variables should be quoted to prevent word-splitting and glob expansion. The kubectl create ns command at line 14 is not idempotent and will fail if the namespace already exists.

Proposed patch
 #!/bin/bash
 # Installs all PMS UI charts
 ## Usage: ./install.sh [kubeconfig]

+set -euo pipefail
+
 if [ $# -ge 1 ] ; then
-  export KUBECONFIG=$1
+  export KUBECONFIG="$1"
 fi

 NS=pms
 CHART_VERSION=1.3.0-develop
 COPY_UTIL=../copy_cm_func.sh

 echo Create $NS namespace
-kubectl create ns $NS
+kubectl create ns "$NS" --dry-run=client -o yaml | kubectl apply -f -

The chart version 1.3.0-develop is defined at helm/pmp-ui-v2/Chart.yaml:5 and is published to the configured Helm repository (https://mosip.github.io).

helm/pmp-ui-v2/values.yaml (1)

52-62: Clarify versioning intent for 1.3.x tag—chart is marked -develop in Chart.yaml.

The values.yaml specifies a floating tag 1.3.x with pullPolicy: Always, which means each restart may pull a different build. While this is acceptable for development releases (Chart.yaml shows version: 1.3.0-develop), clarify whether this is intentional. If graduating to a stable release, pin a concrete tag (e.g., 1.3.0 or 1.3.0-beta.4) for reproducible deployments and clear traceability.

helm/pmp-ui-v2/Chart.yaml (1)

1-6: Clarify Chart.yaml versioning semantics for 1.3.0-develop.

The -develop suffix is used consistently across install scripts and the Helm chart, but it's unconventional for a version intended for release. Semver prerelease syntax (e.g., 1.3.0-beta.1, 1.3.0-rc.1) is clearer for release promotion and automated tooling. Either standardize on a conventional prerelease format or document the -develop convention in your release process.

Also note: appVersion is empty; confirm if this is intentional.

pmp-ui-v2/src/nav/HeaderNav.js (1)

132-146: Add missing dependency to useEffect.

The effect at line 79-146 references isPolicyManager (lines 132, 138) but doesn't include it in the dependency array at line 146. This can lead to stale closures where the effect uses an outdated value of isPolicyManager.

🔧 Proposed fix
-    }, [isEmailVerified]);
+    }, [isEmailVerified, isPolicyManager]);
pmp-ui-v2/src/auth/GuardedRoute.js (1)

45-53: Role substring matching may cause false positives.

Similar to MainLayout.js, using roles?.includes('PARTNER_ADMIN') on a comma-separated string could match partial role names. Consider splitting for exact matching.

🐛 Suggested fix for exact role matching
 const userProfile = getUserProfile();
 const isDashboard = initialPathnameRef.current.split('/').includes('dashboard') ? true : false;
-const isAdmin = userProfile?.roles?.includes("PARTNER_ADMIN") || false;
-const isPolicyManager = userProfile?.roles?.includes("POLICYMANAGER") || false;
+const rolesArray = (userProfile?.roles ?? '').split(',').map(r => r.trim());
+const isAdmin = rolesArray.includes("PARTNER_ADMIN");
+const isPolicyManager = rolesArray.includes("POLICYMANAGER");
 if (userProfile && !isDashboard && !isAdmin && !isPolicyManager) {
pmp-ui-v2/src/pages/admin/policyManager/CreatePolicy.js (1)

111-115: Typo: console.err should be console.error.

console.err is not a valid console method and will throw a runtime error. This should be console.error.

Suggested fix
                 const storedPolicyType = sessionStorage.getItem('activeTab');
                 if (!storedPolicyType) {
-                    console.err('policy Type not found');
+                    console.error('policy Type not found');
                     navigate('/partnermanagement/policy-manager/policy-group-list')
                 }
pmp-ui-v2/src/pages/dashboard/Dashboard.js (1)

770-777: Bug: config flag string check is inconsistent and can render when disabled.
configData.isCaSignedPartnerCertificateAvailable is likely 'true'|'false'; 'false' is truthy, so the count badge can show incorrectly.

Proposed fix
-                {configData && configData.isCaSignedPartnerCertificateAvailable && expiringFtmCertificateCount > 0 && (
+                {configData && configData.isCaSignedPartnerCertificateAvailable === 'true' && expiringFtmCertificateCount > 0 && (
                   <CountWithHover
                     countLabel={expiringFtmCertificateCount}
                     descriptionKey={expiringFtmCertificateCount > 1 ? "dashboard.ftmChipCertExpiryCountDesc1" : "dashboard.ftmChipCertExpiryCountDesc2"}
                     descriptionParams={{ expiringFtmCertificateCount }}
                     isExpiryHover={true}
                   />
                 )}
🤖 Fix all issues with AI agents
In @deploy/uitest-pmp-v2/values.yaml:
- Around line 4-7: The image tag "tag: 1.3.x" in values.yaml is a floating tag
while pullPolicy: Always forces fresh pulls; either document this deliberate
strategy or pin to an immutable tag/digest: add a comment next to image.tag
explaining that 1.3.x is intentional and managed via the release-1.3.x process
(or CI promotion) and confirm who/what updates it, or change image.tag to a
specific semver or image digest and ensure pullPolicy is consistent with
immutability.

In @pmp-ui-v2/public/i18n/ara.json:
- Around line 446-539: Several Arabic strings in the enterPurposeSubtitle* keys
incorrectly reference "title" wording instead of "subtitle"; locate keys like
enterPurposeSubtitleAra, enterPurposeSubtitleInAra (and the
enterPurposeSubtitle* family) and replace the Arabic text to explicitly say
"العنوان الفرعي" (subtitle) rather than "العنوان" or "عنوان" used for title,
ensuring consistency with UI labels/tooltips and matching the corresponding
enterPurposeTitle* translations.

In @pmp-ui-v2/public/i18n/eng.json:
- Around line 1272-1274: The string value for the translation key
"errorInDismiss" contains a typo ("notifcation"); update the JSON entry for key
errorInDismiss to read "Error while dismissing notification" (fixing the missing
'i') so the corrected text appears in the UI wherever errorInDismiss is used.

In @pmp-ui-v2/src/nav/MainLayout.js:
- Around line 119-126: The code uses a string "roles" and checks substrings with
roles.includes('PARTNER_ADMIN') and roles.includes('POLICYMANAGER'), which can
yield false positives; instead split the roles string into an array (e.g.,
roles.split(',') after trimming and filtering empty entries) and perform exact
membership checks to set isPartnerAdmin and isPolicyManager (or normalize
case/whitespace first), so the early return before calling the verify endpoint
only triggers for exact role matches.

In @pmp-ui-v2/src/pages/admin/authenticationServices/EditAdminApiKey.js:
- Around line 53-76: The JSON.parse of
sessionStorage.getItem('selectedApiKeyAttributes') inside the useEffect can
throw on malformed data; wrap the parse in a try-catch around the code that
reads and parses selectedApiKeyAttributes, and on catch call
setUnexpectedError(true), setDataLoaded(true) and return (optionally log the
error) instead of allowing the exception to bubble; keep the existing logic to
setApiKeyDetails, setSelectedDateStr and setOriginalExpiryDate when parsing
succeeds.

In @pmp-ui-v2/src/pages/common/fields/Information.js:
- Around line 32-40: The RTL tooltip on small screens is pushed off-screen by
the `max-800:-right-[800%]` utility in the class string for the tooltip div;
update that token to `max-800:-right-[50%]` so the RTL branch
(`isLoginLanguageRTL ? 'right-6 max-800:-right-[800%]' : 'max-800:left-1/2 
left-6'`) mirrors the LTR centering behavior (`max-800:left-1/2` +
`-translate-x-1/2`) and keeps the tooltip centered and visible on widths below
800px.

In @pmp-ui-v2/src/pages/common/fields/TextInputComponentWithDeleteButton.js:
- Around line 25-39: The getDeleteLabel function is using t(deleteKey, { lng:
langCode }) which forces i18n to load a language bundle that may not exist;
remove the lng override and call t(deleteKey) instead so it reads the key from
the currently loaded resource bundle (keep the existing fallback logic that
checks deleteLabel === deleteKey and returns t('createOidcClient.delete') as
before). Ensure this change is applied inside getDeleteLabel (references:
languageCode, langCode, deleteKey, deleteLabel, and getDeleteLabel).

In @pmp-ui-v2/src/pages/common/OidcClientAdditionalInfoSection.js:
- Around line 184-342: The DOM contains duplicate IDs and unstable React keys:
change the duplicate id attributes used for adding entries (currently
"add_purpose_title_language" and "add_purpose_subtitle_language" which appear on
both a button and a div) so each element has a unique id (e.g., append "_btn" or
"_link" to one of them), and replace key={index} in the purposeTitleEntries.map
and purposeSubtitleEntries.map with key={entry.id} so React uses stable keys and
input/errors won’t mix after deletions; update any associated id references
passed to child components (e.g., purpose_title_lang_*, purpose_subtitle_lang_*,
purpose_title_text_*, purpose_subtitle_text_*) only if you change their naming
to remain unique.
- Around line 130-182: The consent_expiry_label <label> lacks an htmlFor to
associate it with the input; update the label with
htmlFor="consent_expiry_input" so it targets the input element with id
"consent_expiry_input" (used by the consentExpiry value and
handleConsentExpiryChange handler), ensuring screen readers and form
accessibility correctly link the label and input.

In @pmp-ui-v2/src/pages/common/OidcClientDetailsPage.js:
- Around line 264-303: The copy button remains interactive when
oidcClientDetails.status !== "ACTIVE" because onClick always invokes
copyClientId and tabIndex only changes; update the button to be fully disabled
when inactive by adding the disabled attribute (or conditional onClick removal)
and ensure the handler is guarded: only call copyClientId if
oidcClientDetails.status === "ACTIVE"; target the button element with id
oidc_client_details_copy_id and the copy handler copyClientId to implement this
change and keep tabIndex set to "-1" when disabled.

In @pmp-ui-v2/src/pages/dashboard/SelectPolicyPopup.js:
- Around line 227-236: The TextInputComponent call may receive undefined because
getPartnerTypeDescription(...) can return undefined for unknown types; update
the call to provide an explicit fallback (for example replace
textBoxValue={getPartnerTypeDescription(isLinkPolicyGroupPopup ? partnerType :
userprofile.partnerType, t)} with
textBoxValue={getPartnerTypeDescription(isLinkPolicyGroupPopup ? partnerType :
userprofile.partnerType, t) || t('selectPolicyPopup.unknownPartnerType') ||
'Unknown'}), or alternatively update getPartnerTypeDescription in AppUtils.js to
return a default string for unmapped types; ensure you reference
getPartnerTypeDescription, partnerType, userprofile.partnerType and
TextInputComponent when making the change.

In @pmp-ui-v2/src/pages/partner/authenticationServices/EditOidcClient.js:
- Around line 351-365: handleClientNameChange currently only treats
whitespace-only input as required because the condition uses if (value.trim()
=== '' && value !== '') {}; change the logic to treat both empty string and
whitespace-only as required by checking if value.trim() === '' (i.e., remove the
extra value !== '' check) and call
setClientNameError(t('createOidcClient.clientNameRequired')) in that branch;
keep the validateInputRegex and the inputError branch otherwise so regex errors
still override, and ensure setClientNameError("") is used when no errors.
- Around line 1017-1077: There are duplicate DOM ids and unstable React keys in
the clientNameLangMap UI: change the repeated
id="add_client_name_lang_map_entry" so each add-button has a unique id (e.g.,
"add_client_name_lang_map_entry_top" and
"add_client_name_lang_map_entry_inline") and update the map rendering to use
stable keys by replacing key={index} with key={entry.id} in the
clientNameLangMapEntries.map callback (refer to updateClientNameLangMapEntry,
deleteClientNameLangMapEntry and addClientNameLangMapEntry for context).
- Around line 263-316: Replace uses of crypto.randomUUID() with the uuid
package's v4 generator: import { v4 as uuidv4 } from 'uuid' (add/update the
import at the top of EditOidcClient.js and AppUtils.js) and change id generation
calls like `id: \`oidc_name_${crypto.randomUUID()}\``,
`purpose_title_${crypto.randomUUID()}`, and
`purpose_subtitle_${crypto.randomUUID()}` to use `uuidv4()` instead (e.g., `id:
\`oidc_name_${uuidv4()}\``) in all seven locations referenced across
EditOidcClient.js and AppUtils.js. Ensure imports are present and remove/replace
any remaining crypto.randomUUID() usages in those files.
- Around line 179-193: The component sets additionalConfigRequired
asynchronously via isOidcClientAdditionalInfoRequired() in
checkAdditionalConfigSupport() (used in useEffect) but the code later chooses
different endpoints and payload shapes based on additionalConfigRequired (see
createRequest logic and PUT switching between /oidc-clients/{id} and
/oauth/client/{id}), which risks submitting with stale state or mismatched
backend contracts; to fix, confirm with backend that /oidc-clients/{id} and
/oauth/client/{id} are the same resource and accept both payload variants, and
then ensure the UI waits for the async flag before allowing submit (e.g.,
block/disable submit until setAdditionalConfigRequired resolves or re-check flag
synchronously before sending), and reconcile createRequest payloads so the same
schema is sent to whichever endpoint is used (or centralize endpoint selection
logic), applying the same changes in both EditOidcClient.js and
CreateOidcClient.js.

In @pmp-ui-v2/src/pages/partner/certificates/UploadCertificate.js:
- Around line 226-232: The popupData lacks the computed flag
isMispOrAbisPartnerCertificate when selected via PartnerCertificatesList, so
UploadCertificate.js's conditional (popupData.isMispOrAbisPartnerCertificate)
fails for ABIS/MISP partners; update the place that calls
setSelectedPartnerData(partner) in PartnerCertificatesList and the spot that
spreads selectedPartnerData into popupData to include
isMispOrAbisPartnerCertificate: partner.partnerType === "MISP_Partner" ||
partner.partnerType === "ABIS_Partner" (mirror how PartnersList.js sets it) so
the UploadCertificate.js check and partner ID rendering work for ABIS/MISP
partners.

In @pmp-ui-v2/src/pages/partner/policies/RequestPolicy.js:
- Around line 162-164: The code uses isAdminPath before it's declared causing a
temporal dead zone error; move the declaration of isAdminPath (currently
declared later) to the top of the component (before any use such as the if-check
that calls setPartnerType and getPartnerTypeDescription with selectedPartner) so
it's defined when referenced, and remove the duplicate isAdminPath declaration
later to avoid redeclaration.

In @pmp-ui-v2/src/utils/AppUtils.js:
- Around line 1209-1221: The MISP block uses
notification.notificationDetails.mispLicenseKeyDetails[0] without validating the
array; update the MISP handling (the JSX Trans usage and any helper code that
references notification.notificationDetails.mispLicenseKeyDetails at lines
~1209, ~1295, ~1325) to first verify that notification.notificationDetails &&
Array.isArray(notification.notificationDetails.mispLicenseKeyDetails) &&
notification.notificationDetails.mispLicenseKeyDetails.length > 0, then safely
read the firstItem (e.g., const first =
notification.notificationDetails.mispLicenseKeyDetails[0]) and pass fallbacks
for first.mispLicenseKeyName, first.mispPartnerId and first.expiryDateTime into
formatDate/Trans; ensure the same defensive check/fallback logic is applied to
the other occurrences mentioned (around 1295-1307, 1325-1327).
🧹 Nitpick comments (23)
pmp-ui-v2/src/pages/admin/policyRequests/PolicyRequestsList.js (1)

47-47: Pagination preferences migrated to sessionStorage.

These changes align with the broader refactoring to use sessionStorage instead of localStorage across the codebase. The implementation is consistent and correct.

Note that pagination preferences (items per page) will no longer persist across browser sessions. Users will default back to 8 items per page when they reopen the browser. If preserving user preferences across sessions is desired, localStorage would be more appropriate. However, this appears to be an intentional design decision.

Also applies to: 51-51

pmp-ui-v2/src/pages/admin/deviceProviderServices/AdminDevicesList.js (1)

40-44: Harden itemsPerPage initialization (avoid NaN/SSR issues)

Right now Number(sessionStorage.getItem('itemsPerPage')) can become NaN and flow into pagination, and direct sessionStorage access during render can break in non-browser contexts.

Proposed change
-    const [selectedRecordsPerPage, setSelectedRecordsPerPage] = useState(sessionStorage.getItem('itemsPerPage') ? Number(sessionStorage.getItem('itemsPerPage')) : 8);
+    const [selectedRecordsPerPage, setSelectedRecordsPerPage] = useState(() => {
+        if (typeof window === 'undefined') return 8;
+        const raw = sessionStorage.getItem('itemsPerPage');
+        const n = Number(raw);
+        return Number.isFinite(n) && n > 0 ? n : 8;
+    });
@@
-    const [pageSize, setPageSize] = useState(sessionStorage.getItem('itemsPerPage') ? Number(sessionStorage.getItem('itemsPerPage')) : 8);
+    const [pageSize, setPageSize] = useState(() => {
+        if (typeof window === 'undefined') return 8;
+        const raw = sessionStorage.getItem('itemsPerPage');
+        const n = Number(raw);
+        return Number.isFinite(n) && n > 0 ? n : 8;
+    });
pmp-ui-v2/src/pages/partner/policies/ViewPolicyDetails.js (1)

18-19: Consider renaming partnerData to policyData for clarity.

The variable partnerData stores policy attributes, which could be confusing. Renaming it to policyData or policyAttributesData would better reflect its content and improve readability.

♻️ Proposed refactor
-    const partnerData = sessionStorage.getItem('selectedPolicyAttributes');
-    if (partnerData) {
+    const policyData = sessionStorage.getItem('selectedPolicyAttributes');
+    if (policyData) {
         try {
-            const selectedPartner = JSON.parse(partnerData);
+            const selectedPartner = JSON.parse(policyData);
             setPolicyDetails(selectedPartner);
pmp-ui-v2/src/pages/partner/deviceProviderServices/SbiList.js (1)

48-48: Clarify or remove commented cleanup code.

The commented-out sessionStorage.removeItem suggests incomplete cleanup logic. Should this line be uncommented to clear stale session data on mount, or removed entirely if cleanup is unnecessary?

pmp-ui-v2/src/pages/admin/partners/CreatePartner.js (1)

190-204: Consider adding default cases for robustness.

Both helper functions handle only the expected partner type values without a default case. While the dropdown constrains values to MISP_PARTNER and ABIS_PARTNER, adding default cases would make the code more defensive against future changes or unexpected states.

♻️ Suggested improvement
 const getPartnerTypeForDomain = (partnerType) => {
     if (partnerType === "MISP_PARTNER") {
         return "MISP_Partner";
     } else if (partnerType === "ABIS_PARTNER") {
         return "ABIS_Partner";
     }
+    return partnerType; // fallback to original value
 };

 const getUploadCertificateButtonName = (partnerType) => {
     if (partnerType === "MISP_PARTNER") {
         return "createPartner.uploadMispPartnerCertificate";
     } else if (partnerType === "ABIS_PARTNER") {
         return "createPartner.uploadAbisPartnerCertificate";
     }
+    return "createPartner.uploadPartnerCertificate"; // fallback to generic label
 };
pmp-ui-v2/src/pages/dashboard/SelectPolicyPopup.js (1)

234-234: Consider aligning ID naming convention.

The ID select_policyPopup_partner_type uses camelCase in the middle ("policyPopup"), while other IDs in this file use consistent underscores (e.g., select_policy_group_popup_title, select_policy_group_list). Consider using select_policy_popup_partner_type for consistency.

pmp-ui-v2/src/pages/partner/authenticationServices/ApiKeysList.js (1)

106-107: Consider refining the CodeQL suppression comment wording.

The CodeQL suppression comment states the data "does not contain sensitive information," but the stored-xss warning is about cross-site scripting risk rather than data sensitivity. A more precise comment would clarify that the data originates from a trusted backend API.

📝 Suggested comment refinement
-// codeql[js/stored-xss]: Data stored in sessionStorage does not contain sensitive information
+// codeql[js/stored-xss]: Data originates from trusted backend API and is properly handled in the view component

Also applies to: 113-114

pmp-ui-v2/src/pages/partner/policies/RequestPolicy.js (4)

117-126: Consider handling rapid partnerType changes.

The handler correctly resets dependent fields when partnerType changes. However, if a user rapidly switches between partner types, multiple concurrent API requests could be in flight, potentially causing responses to arrive out of order and populate the dropdown with stale data.

Consider implementing request cancellation (e.g., using AbortController) or tracking the latest request to ignore outdated responses.

♻️ Suggested enhancement with AbortController
+const abortControllerRef = useRef(null);
+
 const onChangePartnerType = async (fieldName, selectedValue) => {
+  // Cancel previous request if it exists
+  if (abortControllerRef.current) {
+    abortControllerRef.current.abort();
+  }
+  abortControllerRef.current = new AbortController();
+  
   setPartnerType(selectedValue);
   setPartnerId("");
   setPolicyName("");
   setPolicyGroupName("");
   setPoliciesDropdownData([]);
   setPartnerComment("");
   const apiUrl = `/partners/v3?status=approved&partnerType=${selectedValue}`;
-  await fetchPartnerList(apiUrl);
+  await fetchPartnerList(apiUrl, abortControllerRef.current.signal);
 }

Then update fetchPartnerList to accept and use the signal parameter.


128-152: Consider clearing dropdown data on fetch errors.

The function properly handles loading states and errors. However, when an error occurs, the previous partnerIdDropdownData remains populated, which might confuse users by showing stale partner options that don't match the selected partner type.

Consider resetting the dropdown data on error:

♻️ Suggested improvement
 } catch (err) {
   console.error('Error fetching data:', err);
+  setPartnerIdDropdownData([]);
+  setPartnerData([]);
   if (err.response?.status && err.response.status !== 401) {
     setErrorMsg(err.toString());
   }
   setDataLoaded(true);
 }

313-313: Inconsistent spacing pattern for RTL support.

Line 313 uses mx-1 (margin on both sides), while lines 412 and 439 use conditional spacing ${isLoginLanguageRTL ? "mr-1" : "ml-1"} to properly support RTL languages. However, line 413 and 440 also use mx-1.

For consistency with RTL behavior, consider using the conditional pattern throughout, or verify that horizontal margins on both sides are intentional for these specific labels.

Also applies to: 412-413, 439-440


160-160: Remove debug console.log statement.

This debug logging statement should be removed before merging to production.

🧹 Cleanup suggestion
   const selectedPartner = partnerData.find(item => item.partnerId === selectedValue);
-  console.log("Selected Partner Data: ", selectedPartner);
   if (selectedPartner) {
pmp-ui-v2/src/utils/AppUtils.js (2)

135-156: Minor duplication with getLanguageLabel.

getLanguageDisplayName duplicates the language map from getLanguageLabel (lines 117-124). Consider extracting the shared map to a constant.

♻️ Suggested refactor
+const LANGUAGE_DISPLAY_MAP = {
+    "eng": "English",
+    "hin": "हिन्दी",
+    "ara": "العربية",
+    "fra": "Français",
+    "tam": "தமிழ்",
+    "kan": "ಕನ್ನಡ"
+};
+
 export const getLanguageLabel = (languageCode, t) => {
-    const languageMap = {
-        "eng": "English",
-        ...
-    };
     if (languageCode) {
-        const languageLabel = languageMap[languageCode.toLowerCase()];
+        const languageLabel = LANGUAGE_DISPLAY_MAP[languageCode.toLowerCase()];
         ...
     }
 }

 export const getLanguageDisplayName = (languageCode, t) => {
     if (languageCode === '@none' || languageCode === 'default') {
         return t('createOidcClient.default');
     }
     if (languageCode) {
-        const displayName = displayNameMap[languageCode.toLowerCase()];
+        const displayName = LANGUAGE_DISPLAY_MAP[languageCode.toLowerCase()];
         ...
     }
 }

1586-1603: Consider simplifying error handling in validateOidcEntryText.

The function mutates the errors object via setErrors, but the logic for determining which error to show is complex. The condition on line 1595 checks entry.text.trim() === '' && entry.text !== '' which only matches whitespace-only strings.

pmp-ui-v2/src/pages/admin/authenticationServices/AdminApiKeysList.js (1)

186-193: Unused index parameter in editExpiryDate.

The index parameter is passed but never used within the function. Consider removing it to improve clarity.

Suggested fix
-    const editExpiryDate = (selectedApiKeyData, index) => {
+    const editExpiryDate = (selectedApiKeyData) => {
         if (selectedApiKeyData.status !== "deactivated") {
             setActionId(-1);
             // codeql[js/stored-xss]: Data stored in sessionStorage does not contain sensitive information
             sessionStorage.setItem('selectedApiKeyAttributes', JSON.stringify(selectedApiKeyData));
             navigate('/partnermanagement/admin/authentication-services/edit-api-key');
         }
     };

And update the call site at line 322:

-onClick={() => editExpiryDate(apiKey, index)}
+onClick={() => editExpiryDate(apiKey)}
pmp-ui-v2/src/pages/admin/authenticationServices/EditAdminApiKey.js (1)

67-74: Potential usability issue with default expiry date initialization.

When an API key has no existing expiry date, the code initializes selectedDateStr to today at 23:59:59. However, the validation at lines 100-111 compares dates at start-of-day, meaning today's date will pass validation. But if the user doesn't change the date, isFormValid() at line 203 requires selectedDateStr !== originalExpiryDate, so the submit button remains disabled.

This seems intentional (requiring a change), but consider whether a key with no expiry should default to a future date instead to improve UX.

pmp-ui-v2/src/pages/admin/authenticationServices/AdminOidcClientsList.js (1)

78-86: Inconsistent conditional in checkAdditionalConfigSupport.

The if (isRequired) check on line 81 is redundant since setAdditionalConfigRequired(isRequired) could simply be called unconditionally. If the intent is to avoid unnecessary state updates when isRequired is false, this is fine, but the asymmetry with other similar patterns (like in CreateOidcClient.js which sets both true/false cases) may cause confusion.

♻️ Suggested simplification
     useEffect(() => {
         const checkAdditionalConfigSupport = async () => {
             const isRequired = await isOidcClientAdditionalInfoRequired();
-            if (isRequired) {
             setAdditionalConfigRequired(isRequired);
-            }
         };
         checkAdditionalConfigSupport();
     }, []);
pmp-ui-v2/src/pages/common/OidcClientAdditionalInfoSection.js (3)

44-55: Accordion header: tabIndex should be numeric; consider aria-expanded/aria-controls.

React expects tabIndex={0} (not a string). Also, for better a11y, wire aria-expanded and aria-controls between the header “button” and the collapsible content.


61-128: Toggle switches: structure is reasonable; RTL knob behavior may be off.

Current knob translation (translate-x-4) is LTR-centric; in RTL the switch may animate in the “wrong” direction. Consider flipping translation based on isLoginLanguageRTL.


349-413: PropTypes: error strings likely shouldn’t be isRequired.

consentExpiryError, purposeTitleDefaultError, purposeSubtitleDefaultError commonly represent “no error” as ""/undefined. If callers ever pass undefined, current isRequired will warn. Consider making them optional (or enforce empty-string in callers).

pmp-ui-v2/src/pages/partner/authenticationServices/OidcClientsList.js (2)

45-46: Consider namespacing the sessionStorage key for pagination (itemsPerPage).
Using a global key can cause cross-page interference (one list changes another list’s page size).


73-82: Set additionalConfigRequired directly from the async result (not only when true).
Current code works, but it’s clearer/safer to always set the state based on the fetched value (and helps future refactors).

pmp-ui-v2/src/pages/common/fields/TextInputComponentWithDeleteButton.js (1)

60-75: Good disabled handling + Enter-key support.
Minor a11y: consider localizing the icon alt text (or use empty alt if the adjacent text is always present).

pmp-ui-v2/src/pages/dashboard/Dashboard.js (1)

55-57: Consider moving isSelectPolicyPopupVisible / isUserConsentGiven to useRef (or state).
They currently rely on closure behavior across async calls, which is fragile if you ever introduce concurrent flows.

Also applies to: 60-75, 220-227

Comment on lines 4 to +7
image:
registry: docker.io
repository: mosipid/uitest-pmp-v2
tag: 1.3.0-beta.3
repository: mosipqa/uitest-pmp-v2
tag: 1.3.x
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's explore the repository structure to understand the deployment strategy
git ls-files | head -20

Repository: mosip/partner-management-portal

Length of output: 206


🏁 Script executed:

# Look for relevant documentation files
fd -t f "README|DEPLOY|CHART|VALUES|HELM" -i | head -20

Repository: mosip/partner-management-portal

Length of output: 338


🏁 Script executed:

# Search for other values.yaml files to see if floating tags are a pattern
fd -t f "values.yaml"

Repository: mosip/partner-management-portal

Length of output: 134


🏁 Script executed:

# Check if there's any documentation about image tags in the repository
rg -i "floating.*tag|1\.3\.x|image.*tag" --type yaml --type md --type txt | head -30

Repository: mosip/partner-management-portal

Length of output: 525


🏁 Script executed:

# Look for any helm chart documentation or values documentation
find . -name "Chart.yaml" -o -name "README.md" -o -name "*.md" | grep -E "(deploy|helm|chart)" | head -10

Repository: mosip/partner-management-portal

Length of output: 191


🏁 Script executed:

# Check the README in deploy/uitest-pmp-v2 for deployment guidance
cat deploy/uitest-pmp-v2/README.md

Repository: mosip/partner-management-portal

Length of output: 851


🏁 Script executed:

# Check the main README for context about release strategy
cat README.md | head -50

Repository: mosip/partner-management-portal

Length of output: 773


🏁 Script executed:

# Check the helm chart README for deployment guidance
cat helm/pmp-ui-v2/README.md

Repository: mosip/partner-management-portal

Length of output: 689


🏁 Script executed:

# Check the complete values.yaml in helm/pmp-ui-v2 for full context
cat helm/pmp-ui-v2/values.yaml

Repository: mosip/partner-management-portal

Length of output: 12725


🏁 Script executed:

# Check the Chart.yaml to understand chart versioning
cat helm/pmp-ui-v2/Chart.yaml

Repository: mosip/partner-management-portal

Length of output: 455


🏁 Script executed:

# Check the deployment template to see how imagePullPolicy is used
cat helm/pmp-ui-v2/templates/deployment.yaml | grep -A 10 -B 5 "image:"

Repository: mosip/partner-management-portal

Length of output: 1663


Document the floating tag strategy; pullPolicy: Always is set but consider pinning to immutable tags.

tag: 1.3.x is a moving target that impacts reproducibility across deployments and rollbacks. While pullPolicy: Always is explicitly configured here (ensuring fresh pulls), floating tags still allow different image versions to be deployed at different times.

If the 1.3.x tag is intentional as part of your release strategy (aligned with the release-1.3.x branch), add a comment in the values.yaml explaining this choice and confirming that image updates for 1.3.x are managed in a controlled way. Otherwise, consider pinning to a specific immutable tag or digest.

🤖 Prompt for AI Agents
In @deploy/uitest-pmp-v2/values.yaml around lines 4 - 7, The image tag "tag:
1.3.x" in values.yaml is a floating tag while pullPolicy: Always forces fresh
pulls; either document this deliberate strategy or pin to an immutable
tag/digest: add a comment next to image.tag explaining that 1.3.x is intentional
and managed via the release-1.3.x process (or CI promotion) and confirm who/what
updates it, or change image.tag to a specific semver or image digest and ensure
pullPolicy is consistent with immutability.

Comment on lines +446 to +539
"partnerIdTooltip": "تتوفر فقط معرفات شركاء المصادقة التي تم تحميل شهادة الشريك الخاصة بها في القائمة المنسدلة. إذا لم تجد معرف الشريك الخاص بك، فيرجى تحميل شهادة الشريك أولاً",
"primaryInformation": "معلومات أساسية",
"additionalInformation": "معلومات إضافية",
"forgotPasswordBanner": "لافتة نسيت كلمة المرور مطلوبة",
"forgotPasswordBannerTooltip": "قم بتمكين هذا الخيار لعرض رابط 'نسيت كلمة المرور' على شاشة مصادقة eSignet.",
"signUpBanner": "لافتة التسجيل مطلوبة",
"signUpBannerTooltip": "قم بتمكين هذا الخيار لعرض رابط 'التسجيل' على شاشة مصادقة eSignet.",
"consentExpiryDuration": "مدة انتهاء الموافقة (بالدقائق)",
"consentExpiryDurationTooltip": "المدة (بالدقائق) التي تظل فيها موافقة المستخدم صالحة قبل إعادة المطالبة.",
"consentExpiryValidation": "الرجاء إدخال قيمة لا تقل عن 10 دقائق.",
"consentExpiryRequired": "مدة انتهاء الموافقة مطلوبة.",
"mins": "دقائق",
"userInfoResponseType": "نوع استجابة معلومات المستخدم",
"selectUserInfoResponseType": "حدد نوع استجابة معلومات المستخدم",
"userInfoResponseTypeTooltip": "يحدد التنسيق الذي سيتم إرجاع معلومات المستخدم به.",
"jws": "JWS",
"jwe": "JWE",
"purposeType": "نوع الغرض",
"selectPurposeType": "حدد نوع الغرض",
"login": "تسجيل الدخول",
"link": "رابط",
"verify": "التحقق",
"purposeTitle": "عنوان الغرض (متعدد اللغات)",
"purposeSubtitle": "العنوان الفرعي للغرض (متعدد اللغات)",
"purposeTitleTooltip": "أدخل عنوان الغرض بلغات متعددة. سيتم استخدام اللغة الافتراضية كبديل.",
"purposeSubtitleTooltip": "أدخل العنوان الفرعي للغرض بلغات متعددة. سيتم استخدام اللغة الافتراضية كبديل.",
"enterPurposeTitle": "أدخل عنوان الغرض بلغتك الأساسية.",
"enterPurposeSubtitle": "أدخل العنوان الفرعي للغرض بلغتك الأساسية.",
"enterNameForOidcClientDefault": "الرجاء إدخال اسم عميل OIDC",
"enterNameForOidcClientEng": "الرجاء إدخال اسم عميل OIDC بالإنجليزية",
"enterNameForOidcClientHin": "الرجاء إدخال اسم عميل OIDC بالهندية",
"enterNameForOidcClientAra": "الرجاء إدخال اسم عميل OIDC بالعربية",
"enterNameForOidcClientFra": "الرجاء إدخال اسم عميل OIDC بالفرنسية",
"enterNameForOidcClientTam": "الرجاء إدخال اسم عميل OIDC بالتاميلية",
"enterNameForOidcClientKan": "الرجاء إدخال اسم عميل OIDC بالكانادا",
"enterPurposeTitleDefault": "أدخل عنوان الغرض باللغة الأساسية الخاصة بك.",
"enterPurposeTitleEng": "أدخل عنوان الغرض باللغة الإنجليزية",
"enterPurposeTitleHin": "أدخل عنوان الغرض باللغة الهندية",
"enterPurposeTitleAra": "أدخل عنوان الغرض باللغة العربية",
"enterPurposeTitleFra": "أدخل عنوان الغرض باللغة الفرنسية",
"enterPurposeTitleTam": "أدخل عنوان الغرض باللغة التاميلية",
"enterPurposeTitleKan": "أدخل عنوان الغرض باللغة الكانادا",
"enterPurposeSubtitleDefault": "أدخل الغرض من العنوان الفرعي بلغتك الأساسية.",
"enterPurposeSubtitleEng": "أدخل عنوان الغرض باللغة الإنجليزية",
"enterPurposeSubtitleHin": "أدخل عنوان الغرض باللغة الهندية",
"enterPurposeSubtitleAra": "أدخل عنوان الغرض باللغة العربية",
"enterPurposeSubtitleFra": "أدخل عنوان الغرض باللغة الفرنسية",
"enterPurposeSubtitleTam": "أدخل عنوان الغرض باللغة التاميلية",
"enterPurposeSubtitleKan": "أدخل عنوان الغرض باللغة الكانادا",
"enterNameForOidcClientInAra": "الرجاء إدخال اسم عميل OIDC بالعربية",
"enterNameForOidcClientInHin": "कृपया OIDC क्लाइंट का नाम हिंदी में दर्ज करें",
"enterNameForOidcClientInFra": "Veuillez entrer le nom du client OIDC en français",
"enterNameForOidcClientInEng": "Please enter the OIDC client name in English",
"enterNameForOidcClientInTam": "தயவுசெய்து OIDC கிளையண்ட் பெயரை தமிழில் உள்ளிடவும்",
"enterNameForOidcClientInKan": "ದಯವಿಟ್ಟು OIDC ಕ್ಲೈಂಟ್ ಹೆಸರನ್ನು ಕನ್ನಡದಲ್ಲಿ ನಮೂದಿಸಿ",
"enterPurposeTitleInAra": "أدخل عنوان الغرض باللغة العربية",
"enterPurposeTitleInHin": "कृपया हिंदी में उद्देश्य शीर्षक दर्ज करें",
"enterPurposeTitleInFra": "Saisissez le titre de l'objet en français",
"enterPurposeTitleInEng": "Enter the Purpose Title in English",
"enterPurposeTitleInTam": "தயவுசெய்து தமிழில் நோக்கத்தின் தலைப்பை உள்ளிடவும்",
"enterPurposeTitleInKan": "ದಯವಿಟ್ಟು ಕನ್ನಡದಲ್ಲಿ ಉದ್ದೇಶ ಶೀರ್ಷಿಕೆಯನ್ನು ನಮೂದಿಸಿ",
"enterPurposeSubtitleInAra": "أدخل العنوان الفرعي للغرض باللغة العربية",
"enterPurposeSubtitleInHin": "कृपया हिंदी में उद्देश्य उपशीर्षक दर्ज करें",
"enterPurposeSubtitleInFra": "Saisissez le sous-titre de l'objectif en français",
"enterPurposeSubtitleInEng": "Enter the Purpose Subtitle in English",
"enterPurposeSubtitleInTam": "தயவுசெய்து தமிழில் நோக்கத்தின் உபதலைப்பை உள்ளிடவும்",
"enterPurposeSubtitleInKan": "ದಯವಿಟ್ಟು ಕನ್ನಡದಲ್ಲಿ ಉದ್ದೇಶ ಉಪಶೀರ್ಷಿಕೆಯನ್ನು ನಮೂದಿಸಿ",
"addLanguage": "إضافة لغة",
"selectLanguage": "حدد اللغة",
"default": "افتراضي",
"purposeTitleRequired": "عنوان الغرض لا يمكن أن يكون فارغًا",
"purposeSubtitleRequired": "العنوان الفرعي للغرض لا يمكن أن يكون فارغًا",
"duplicateLanguage": "يمكن استخدام كل لغة مرة واحدة فقط",
"clientNameTooltip": "أدخل اسم العميل بلغات متعددة. سيتم استخدام اللغة الافتراضية كبديل.",
"clientNameRequired": "اسم العميل لا يمكن أن يكون فارغًا",
"consentExpiryPlaceholder": "أدخل المدة بالدقائق",
"purposeTypeTooltip": "حدد نوع الغرض لعميل OIDC",
"addTitle": "إضافة عنوان",
"addSubtitle": "إضافة عنوان فرعي",
"addTitleHelperText": "انقر على إضافة عنوان لإضافة عنوان متعدد اللغات",
"addSubtitleHelperText": "انقر على إضافة عنوان فرعي لإضافة عنوان فرعي متعدد اللغات",
"defaultLanguageRequired": "اللغة الافتراضية مطلوبة عند إضافة الإدخالات",
"clientNamePlaceholder": "أدخل اسم عميل OIDC",
"clientNameMultilanguage": "اسم عميل OIDC (دعم متعدد اللغات)",
"clientNameMultilanguageTooltip": "أدخل اسم العميل بلغات متعددة. هذا اختياري وسيتم إرساله ككائن فارغ إذا لم تتم إضافة إدخالات.",
"addClientNameLangMap": "إضافة لغة اسم العميل",
"addClientNameLangMapHelperText": "انقر على إضافة لغة اسم العميل لإضافة اسم عميل متعدد اللغات",
"deleteInAra": "حذف",
"deleteInHin": "हटाएं",
"deleteInFra": "Supprimer",
"deleteInEng": "Delete",
"deleteInTam": "நீக்கு",
"deleteInKan": "ಅಳಿಸಿ",
"compatibilityMsg": "ملاحظة: تم تعطيل حقول المعلومات الإضافية ذات الصلة لأن إصدار Esignet المستخدم حاليًا في منصة MOSIP لا يدعمها."
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

New OIDC “Additional Information” i18n block: please spot-check Arabic prompt accuracy.

Some newly added Arabic strings for the “Purpose Subtitle” prompts appear to reference “title” wording (e.g., keys in the enterPurposeSubtitle* family). Please verify these are intentional and match UI labels/tooltips.

🤖 Prompt for AI Agents
In @pmp-ui-v2/public/i18n/ara.json around lines 446 - 539, Several Arabic
strings in the enterPurposeSubtitle* keys incorrectly reference "title" wording
instead of "subtitle"; locate keys like enterPurposeSubtitleAra,
enterPurposeSubtitleInAra (and the enterPurposeSubtitle* family) and replace the
Arabic text to explicitly say "العنوان الفرعي" (subtitle) rather than "العنوان"
or "عنوان" used for title, ensuring consistency with UI labels/tooltips and
matching the corresponding enterPurposeTitle* translations.

Comment on lines +1272 to +1274
"errorInDismiss": "Error while dismissing notifcation",
"mispLicenseKeyExpiry": "MISP License Key Expiration",
"mispLicenseKeyExpiryDescription": "MISP License Key with name: <span>{{mispLicenseKeyName}}</span> for partner <span>{{mispPartnerId}}</span> is set to expire on <span>{{expiryDateTime}}</span>. Renew it now to avoid any disruptions."
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo: “notifcation” → “notification”.

This is user-facing and will show up in the UI.

Proposed fix
-        "errorInDismiss": "Error while dismissing notifcation",
+        "errorInDismiss": "Error while dismissing notification",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"errorInDismiss": "Error while dismissing notifcation",
"mispLicenseKeyExpiry": "MISP License Key Expiration",
"mispLicenseKeyExpiryDescription": "MISP License Key with name: <span>{{mispLicenseKeyName}}</span> for partner <span>{{mispPartnerId}}</span> is set to expire on <span>{{expiryDateTime}}</span>. Renew it now to avoid any disruptions."
"errorInDismiss": "Error while dismissing notification",
"mispLicenseKeyExpiry": "MISP License Key Expiration",
"mispLicenseKeyExpiryDescription": "MISP License Key with name: <span>{{mispLicenseKeyName}}</span> for partner <span>{{mispPartnerId}}</span> is set to expire on <span>{{expiryDateTime}}</span>. Renew it now to avoid any disruptions."
🤖 Prompt for AI Agents
In @pmp-ui-v2/public/i18n/eng.json around lines 1272 - 1274, The string value
for the translation key "errorInDismiss" contains a typo ("notifcation"); update
the JSON entry for key errorInDismiss to read "Error while dismissing
notification" (fixing the missing 'i') so the corrected text appears in the UI
wherever errorInDismiss is used.

Comment on lines +119 to +126
const roles = userProfile.roles ?? '';
const isPartnerAdmin = roles.includes('PARTNER_ADMIN');
const isPolicyManager = roles.includes('POLICYMANAGER');

// Don't call verify endpoint if user is partner admin or policy manager
if (isPartnerAdmin || isPolicyManager) {
return;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Role substring matching may cause false positives.

Using roles.includes('PARTNER_ADMIN') on a comma-separated string could match unintended role names (e.g., SUPER_PARTNER_ADMIN would match). Consider splitting the string first for exact matching.

🐛 Suggested fix for exact role matching
 const userProfile = getUserProfile();
 const roles = userProfile.roles ?? '';
-const isPartnerAdmin = roles.includes('PARTNER_ADMIN');
-const isPolicyManager = roles.includes('POLICYMANAGER');
+const rolesArray = roles.split(',').map(r => r.trim());
+const isPartnerAdmin = rolesArray.includes('PARTNER_ADMIN');
+const isPolicyManager = rolesArray.includes('POLICYMANAGER');

 // Don't call verify endpoint if user is partner admin or policy manager
 if (isPartnerAdmin || isPolicyManager) {
     return;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const roles = userProfile.roles ?? '';
const isPartnerAdmin = roles.includes('PARTNER_ADMIN');
const isPolicyManager = roles.includes('POLICYMANAGER');
// Don't call verify endpoint if user is partner admin or policy manager
if (isPartnerAdmin || isPolicyManager) {
return;
}
const roles = userProfile.roles ?? '';
const rolesArray = roles.split(',').map(r => r.trim());
const isPartnerAdmin = rolesArray.includes('PARTNER_ADMIN');
const isPolicyManager = rolesArray.includes('POLICYMANAGER');
// Don't call verify endpoint if user is partner admin or policy manager
if (isPartnerAdmin || isPolicyManager) {
return;
}
🤖 Prompt for AI Agents
In @pmp-ui-v2/src/nav/MainLayout.js around lines 119 - 126, The code uses a
string "roles" and checks substrings with roles.includes('PARTNER_ADMIN') and
roles.includes('POLICYMANAGER'), which can yield false positives; instead split
the roles string into an array (e.g., roles.split(',') after trimming and
filtering empty entries) and perform exact membership checks to set
isPartnerAdmin and isPolicyManager (or normalize case/whitespace first), so the
early return before calling the verify endpoint only triggers for exact role
matches.

Comment on lines +53 to +76
useEffect(() => {
const data = sessionStorage.getItem('selectedApiKeyAttributes');
if (!data) {
setUnexpectedError(true);
setDataLoaded(true);
return;
}
const apiKeyData = JSON.parse(data);
setApiKeyDetails(apiKeyData);

// Initialize expiry date
if (apiKeyData?.apiKeyExpiryDateTime) {
setSelectedDateStr(apiKeyData.apiKeyExpiryDateTime);
setOriginalExpiryDate(apiKeyData.apiKeyExpiryDateTime);
} else {
// Initialize with today's date as default
const today = new Date();
today.setHours(23, 59, 59, 999);
const todayISO = today.toISOString();
setSelectedDateStr(todayISO);
setOriginalExpiryDate(todayISO);
}
setDataLoaded(true);
}, []);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing try-catch around JSON.parse for sessionStorage data.

If the selectedApiKeyAttributes data in sessionStorage is corrupted or malformed, JSON.parse at line 60 will throw an uncaught exception. Consider wrapping it in a try-catch block.

Suggested fix
     useEffect(() => {
         const data = sessionStorage.getItem('selectedApiKeyAttributes');
         if (!data) {
             setUnexpectedError(true);
             setDataLoaded(true);
             return;
         }
-        const apiKeyData = JSON.parse(data);
+        let apiKeyData;
+        try {
+            apiKeyData = JSON.parse(data);
+        } catch (e) {
+            console.error('Error parsing API key data:', e);
+            setUnexpectedError(true);
+            setDataLoaded(true);
+            return;
+        }
         setApiKeyDetails(apiKeyData);
         
         // Initialize expiry date
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
const data = sessionStorage.getItem('selectedApiKeyAttributes');
if (!data) {
setUnexpectedError(true);
setDataLoaded(true);
return;
}
const apiKeyData = JSON.parse(data);
setApiKeyDetails(apiKeyData);
// Initialize expiry date
if (apiKeyData?.apiKeyExpiryDateTime) {
setSelectedDateStr(apiKeyData.apiKeyExpiryDateTime);
setOriginalExpiryDate(apiKeyData.apiKeyExpiryDateTime);
} else {
// Initialize with today's date as default
const today = new Date();
today.setHours(23, 59, 59, 999);
const todayISO = today.toISOString();
setSelectedDateStr(todayISO);
setOriginalExpiryDate(todayISO);
}
setDataLoaded(true);
}, []);
useEffect(() => {
const data = sessionStorage.getItem('selectedApiKeyAttributes');
if (!data) {
setUnexpectedError(true);
setDataLoaded(true);
return;
}
let apiKeyData;
try {
apiKeyData = JSON.parse(data);
} catch (e) {
console.error('Error parsing API key data:', e);
setUnexpectedError(true);
setDataLoaded(true);
return;
}
setApiKeyDetails(apiKeyData);
// Initialize expiry date
if (apiKeyData?.apiKeyExpiryDateTime) {
setSelectedDateStr(apiKeyData.apiKeyExpiryDateTime);
setOriginalExpiryDate(apiKeyData.apiKeyExpiryDateTime);
} else {
// Initialize with today's date as default
const today = new Date();
today.setHours(23, 59, 59, 999);
const todayISO = today.toISOString();
setSelectedDateStr(todayISO);
setOriginalExpiryDate(todayISO);
}
setDataLoaded(true);
}, []);
🤖 Prompt for AI Agents
In @pmp-ui-v2/src/pages/admin/authenticationServices/EditAdminApiKey.js around
lines 53 - 76, The JSON.parse of
sessionStorage.getItem('selectedApiKeyAttributes') inside the useEffect can
throw on malformed data; wrap the parse in a try-catch around the code that
reads and parses selectedApiKeyAttributes, and on catch call
setUnexpectedError(true), setDataLoaded(true) and return (optionally log the
error) instead of allowing the exception to bubble; keep the existing logic to
setApiKeyDetails, setSelectedDateStr and setOriginalExpiryDate when parsing
succeeds.

Comment on lines +351 to +365
const handleClientNameChange = (value) => {
setClientName(value);
let inputError = "";
validateInputRegex(value, (error) => {
inputError = error;
}, t);

if (value.trim() === '' && value !== '') {
setClientNameError(t('createOidcClient.clientNameRequired'));
} else if (inputError) {
setClientNameError(inputError);
} else {
setClientNameError("");
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Client name required validation misses the empty-string case.
Right now value === '' won’t set clientNameRequired (it only triggers on whitespace-only strings).

Proposed fix
-        if (value.trim() === '' && value !== '') {
+        if (value.trim() === '') {
             setClientNameError(t('createOidcClient.clientNameRequired'));
         } else if (inputError) {
             setClientNameError(inputError);
         } else {
             setClientNameError("");
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleClientNameChange = (value) => {
setClientName(value);
let inputError = "";
validateInputRegex(value, (error) => {
inputError = error;
}, t);
if (value.trim() === '' && value !== '') {
setClientNameError(t('createOidcClient.clientNameRequired'));
} else if (inputError) {
setClientNameError(inputError);
} else {
setClientNameError("");
}
};
const handleClientNameChange = (value) => {
setClientName(value);
let inputError = "";
validateInputRegex(value, (error) => {
inputError = error;
}, t);
if (value.trim() === '') {
setClientNameError(t('createOidcClient.clientNameRequired'));
} else if (inputError) {
setClientNameError(inputError);
} else {
setClientNameError("");
}
};
🤖 Prompt for AI Agents
In @pmp-ui-v2/src/pages/partner/authenticationServices/EditOidcClient.js around
lines 351 - 365, handleClientNameChange currently only treats whitespace-only
input as required because the condition uses if (value.trim() === '' && value
!== '') {}; change the logic to treat both empty string and whitespace-only as
required by checking if value.trim() === '' (i.e., remove the extra value !== ''
check) and call setClientNameError(t('createOidcClient.clientNameRequired')) in
that branch; keep the validateInputRegex and the inputError branch otherwise so
regex errors still override, and ensure setClientNameError("") is used when no
errors.

Comment on lines +1017 to +1077
<button
type="button"
id="add_client_name_lang_map_entry"
className="bg-[#1447b2] text-white font-semibold text-sm px-6 py-2 rounded-md cursor-pointer hover:bg-[#0f3a8a] transition-colors"
tabIndex="0"
onKeyDown={(e) => onPressEnterKey(e, addClientNameLangMapEntry)}
onClick={addClientNameLangMapEntry}
>
{t('createOidcClient.addClientNameLangMap')}
</button>
<p className="text-gray-400 text-sm mt-2 text-center">
{t('createOidcClient.addClientNameLangMapHelperText')}
</p>
</div>
) : (
<div className="bg-white border border-neutral-300 shadow-sm rounded-md p-4">
{clientNameLangMapEntries.map((entry, index) => {
const availableLangs = getAvailableOidcLanguages(entry.id, clientNameLangMapEntries, languageDropdownData, true);
return (
<div key={index} className="flex mb-2">
<div className="w-1/3">
<DropdownComponent
fieldName={`clientNameLangMapLang_${index + 1}`}
dropdownDataList={availableLangs}
onDropDownChangeEvent={(field, value) => updateClientNameLangMapEntry(entry.id, 'language', value)}
fieldNameKey=""
placeHolderKey="createOidcClient.selectLanguage"
selectedDropdownValue={entry.language}
styleSet={styles}
id={`client_name_lang_map_lang_${index + 1}`} />
</div>
<div className={`w-full mt-1 ${isLoginLanguageRTL ? 'mr-5' : 'ml-5'}`}>
<TextInputComponentWithDeleteButton
value={entry.text}
onChange={(e) => updateClientNameLangMapEntry(entry.id, 'text', e.target.value)}
onDelete={() => deleteClientNameLangMapEntry(entry.id)}
placeholder={getOidcPlaceholderForLanguage(entry.language, 'NameForOidcClient', t)}
id={`client_name_lang_map_text_${index + 1}`}
maxLength={256}
showDelete={clientNameLangMapEntries.length > 0}
errorMessage={clientNameLangMapErrors[entry.id]}
isRTL={isLangRTL(entry.language)}
languageCode={entry.language}
/>
</div>
</div>
);
})}
{clientNameLangMapEntries.length < languageDropdownData.filter(lang => lang.fieldValue !== 'default').length && (
<div
role="button"
id="add_client_name_lang_map_entry"
className="text-[#1447b2] font-bold text-xs w-fit cursor-pointer"
tabIndex="0"
onKeyDown={(e) => onPressEnterKey(e, addClientNameLangMapEntry)}
onClick={addClientNameLangMapEntry}
>
<span className="text-lg text-center">+</span>
<span>{t('createOidcClient.addNew')}</span>
</div>
)}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Duplicate DOM id + unstable React keys in the multi-language section.

  • id="add_client_name_lang_map_entry" is used twice.
  • key={index} should be key={entry.id} to avoid remount glitches when deleting/reordering.
Proposed fix
-                                                                            <button
+                                                                            <button
                                                                                 type="button"
-                                                                                id="add_client_name_lang_map_entry"
+                                                                                id="add_client_name_lang_map_entry_empty_state"
                                                                                 className="bg-[#1447b2] text-white font-semibold text-sm px-6 py-2 rounded-md cursor-pointer hover:bg-[#0f3a8a] transition-colors"
                                                                                 tabIndex="0"
                                                                                 onKeyDown={(e) => onPressEnterKey(e, addClientNameLangMapEntry)}
                                                                                 onClick={addClientNameLangMapEntry}
                                                                             >
@@
-                                                                            {clientNameLangMapEntries.map((entry, index) => {
+                                                                            {clientNameLangMapEntries.map((entry, index) => {
                                                                                 const availableLangs = getAvailableOidcLanguages(entry.id, clientNameLangMapEntries, languageDropdownData, true);
                                                                                 return (
-                                                                                    <div key={index} className="flex mb-2">
+                                                                                    <div key={entry.id} className="flex mb-2">
@@
-                                                                                <div
+                                                                                <div
                                                                                     role="button"
-                                                                                    id="add_client_name_lang_map_entry"
+                                                                                    id="add_client_name_lang_map_entry"
                                                                                     className="text-[#1447b2] font-bold text-xs w-fit cursor-pointer"
                                                                                     tabIndex="0"
                                                                                     onKeyDown={(e) => onPressEnterKey(e, addClientNameLangMapEntry)}
                                                                                     onClick={addClientNameLangMapEntry}
                                                                                 >
🤖 Prompt for AI Agents
In @pmp-ui-v2/src/pages/partner/authenticationServices/EditOidcClient.js around
lines 1017 - 1077, There are duplicate DOM ids and unstable React keys in the
clientNameLangMap UI: change the repeated id="add_client_name_lang_map_entry" so
each add-button has a unique id (e.g., "add_client_name_lang_map_entry_top" and
"add_client_name_lang_map_entry_inline") and update the map rendering to use
stable keys by replacing key={index} with key={entry.id} in the
clientNameLangMapEntries.map callback (refer to updateClientNameLangMapEntry,
deleteClientNameLangMapEntry and addClientNameLangMapEntry for context).

Comment on lines +226 to 232
{popupData.isMispOrAbisPartnerCertificate ? (
<p
id='upload_certificate_popup_partner_id_field'
className={`text-xs font-bold text-[#717171] ${isLoginLanguageRTL ? "text-right" : "text-left"}`}
className={`text-xs font-bold text-[#717171]`}
>
# {request.partnerId}
</p>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for where isMispOrAbisPartnerCertificate is set
echo "=== Searching for isMispOrAbisPartnerCertificate property assignments ==="
rg -n "isMispOrAbisPartnerCertificate\s*[:=]" --type=js --type=jsx

# Search for UploadCertificate component usage to verify popupData
echo -e "\n=== Searching for UploadCertificate component invocations ==="
rg -n -B3 -A3 "<UploadCertificate" --type=js --type=jsx

# Search for ABIS partner certificate handling
echo -e "\n=== Searching for ABIS partner certificate references ==="
rg -n -i "abis.*partner.*certificate|abis.*cert" --type=js --type=jsx -C2

Repository: mosip/partner-management-portal

Length of output: 371


🏁 Script executed:

#!/bin/bash
# Search for where isMispOrAbisPartnerCertificate is set
echo "=== Searching for isMispOrAbisPartnerCertificate property assignments ==="
rg -n "isMispOrAbisPartnerCertificate\s*[:=]"

# Search for UploadCertificate component usage
echo -e "\n=== Searching for UploadCertificate component invocations ==="
rg -n -B3 -A3 "<UploadCertificate"

# Search for ABIS partner certificate handling
echo -e "\n=== Searching for ABIS partner certificate references ==="
rg -n -i "abis.*partner.*certificate|abis.*cert" -C2

# Search for where popupData is populated with isMispOrAbisPartnerCertificate
echo -e "\n=== Searching for popupData object construction ==="
rg -n "isMisp.*Partner.*Certificate\s*[:=]" -C3

Repository: mosip/partner-management-portal

Length of output: 50389


🏁 Script executed:

#!/bin/bash
# Look at CreatePartner.js to see how uploadCertificateData is constructed
echo "=== CreatePartner.js uploadCertificateData construction ==="
rg -n -B5 -A8 "uploadCertificateData\s*=" pmp-ui-v2/src/pages/admin/partners/CreatePartner.js

# Look at PartnerCertificatesList.js to see how popupData is constructed
echo -e "\n=== PartnerCertificatesList.js popupData construction ==="
rg -n -B5 -A5 "popupData.*selectedPartnerData" pmp-ui-v2/src/pages/partner/certificates/PartnerCertificatesList.js

# Check UploadCertificate.js to see if it handles both property forms
echo -e "\n=== UploadCertificate.js property checks ==="
rg -n "isMisp.*Partner.*Certificate|isAbis.*Partner.*Certificate" pmp-ui-v2/src/pages/partner/certificates/UploadCertificate.js

Repository: mosip/partner-management-portal

Length of output: 1623


🏁 Script executed:

#!/bin/bash
# Search for where selectedPartnerData is set in PartnerCertificatesList
echo "=== Finding selectedPartnerData assignments ==="
rg -n "selectedPartnerData\s*=" pmp-ui-v2/src/pages/partner/certificates/PartnerCertificatesList.js

# Also check what properties partner object has
echo -e "\n=== Looking for where partner data comes from ==="
rg -n -B3 -A3 "clickOnUpload" pmp-ui-v2/src/pages/partner/certificates/PartnerCertificatesList.js | head -30

# Check if request.partnerId is set anywhere for both partner types
echo -e "\n=== Looking for partner ID handling ==="
rg -n "partnerId\s*[:=]" pmp-ui-v2/src/pages/partner/certificates/PartnerCertificatesList.js

Repository: mosip/partner-management-portal

Length of output: 2250


🏁 Script executed:

#!/bin/bash
# Get the full clickOnUpload function
echo "=== Full clickOnUpload function in PartnerCertificatesList ==="
rg -n -A20 "const clickOnUpload = " pmp-ui-v2/src/pages/partner/certificates/PartnerCertificatesList.js

# Also search for where selectedPartnerData state is set/initialized
echo -e "\n=== selectedPartnerData state and usage ==="
rg -n "setSelectedPartnerData\|selectedPartnerData" pmp-ui-v2/src/pages/partner/certificates/PartnerCertificatesList.js | head -20

Repository: mosip/partner-management-portal

Length of output: 945


Address incomplete ABIS partner integration in PartnerCertificatesList

The isMispOrAbisPartnerCertificate property is not being set in the popupData when the upload certificate flow is triggered through PartnerCertificatesList. On line 42, setSelectedPartnerData(partner) passes the raw partner object, which lacks this computed property. While PartnersList.js correctly sets this property on line 332 (isMispOrAbisPartnerCertificate: partner.partnerType === "MISP_Partner" || partner.partnerType === "ABIS_Partner"), PartnerCertificatesList.js does not compute or include this property when spreading selectedPartnerData into popupData on line 232. This breaks the partner ID rendering for ABIS partners in the self-service flow. The request.partnerId field is correctly available, but the conditional check on line 226 of UploadCertificate.js will fail for ABIS partners accessed through PartnerCertificatesList.

🤖 Prompt for AI Agents
In @pmp-ui-v2/src/pages/partner/certificates/UploadCertificate.js around lines
226 - 232, The popupData lacks the computed flag isMispOrAbisPartnerCertificate
when selected via PartnerCertificatesList, so UploadCertificate.js's conditional
(popupData.isMispOrAbisPartnerCertificate) fails for ABIS/MISP partners; update
the place that calls setSelectedPartnerData(partner) in PartnerCertificatesList
and the spot that spreads selectedPartnerData into popupData to include
isMispOrAbisPartnerCertificate: partner.partnerType === "MISP_Partner" ||
partner.partnerType === "ABIS_Partner" (mirror how PartnersList.js sets it) so
the UploadCertificate.js check and partner ID rendering work for ABIS/MISP
partners.

Comment on lines +162 to +164
if (!isAdminPath) {
setPartnerType(getPartnerTypeDescription(selectedPartner.partnerType, t));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix temporal dead zone error: isAdminPath used before declaration.

Line 162 references isAdminPath, but this variable is not declared until line 225. This will cause a ReferenceError due to JavaScript's temporal dead zone for const declarations.

🐛 Proposed fix

Move the isAdminPath declaration to the top of the component, before any usage:

 function RequestPolicy() {
   const navigate = useNavigate();
   const location = useLocation();
   const { t } = useTranslation();
   const isLoginLanguageRTL = isLangRTL(getUserProfile().locale);
+  const isAdminPath = location.pathname.includes('admin');
   const [dataLoaded, setDataLoaded] = useState(true);
   ...

Then remove the duplicate declaration at line 225.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @pmp-ui-v2/src/pages/partner/policies/RequestPolicy.js around lines 162 -
164, The code uses isAdminPath before it's declared causing a temporal dead zone
error; move the declaration of isAdminPath (currently declared later) to the top
of the component (before any use such as the if-check that calls setPartnerType
and getPartnerTypeDescription with selectedPartner) so it's defined when
referenced, and remove the duplicate isAdminPath declaration later to avoid
redeclaration.

Comment on lines +1209 to 1221
} else if (notification.notificationType === 'MISP_LICENSE_KEY_EXPIRY') {
return (
<Trans
i18nKey="viewAllNotifications.mispLicenseKeyExpiryDescription"
values={{
mispLicenseKeyName: notification.notificationDetails.mispLicenseKeyDetails[0].mispLicenseKeyName ? notification.notificationDetails.mispLicenseKeyDetails[0].mispLicenseKeyName : '-',
mispPartnerId: notification.notificationDetails.mispLicenseKeyDetails[0].mispPartnerId,
expiryDateTime: formatDate(notification.notificationDetails.mispLicenseKeyDetails[0].expiryDateTime, 'dateInWords')
}}
components={{ span: <span className={`font-semibold md:whitespace-nowrap md:break-words break-all`} /> }}
/>
);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential null pointer access in MISP notification handling.

The code accesses notification.notificationDetails.mispLicenseKeyDetails[0] without checking if mispLicenseKeyDetails exists or has elements. This could cause a runtime error if the data is malformed.

🛡️ Suggested defensive check
 } else if (notification.notificationType === 'MISP_LICENSE_KEY_EXPIRY') {
+    const mispDetails = notification.notificationDetails?.mispLicenseKeyDetails?.[0];
+    if (!mispDetails) return null;
     return (
         <Trans 
             i18nKey="viewAllNotifications.mispLicenseKeyExpiryDescription"
             values={{
-                mispLicenseKeyName: notification.notificationDetails.mispLicenseKeyDetails[0].mispLicenseKeyName ? notification.notificationDetails.mispLicenseKeyDetails[0].mispLicenseKeyName : '-',
-                mispPartnerId: notification.notificationDetails.mispLicenseKeyDetails[0].mispPartnerId,
-                expiryDateTime: formatDate(notification.notificationDetails.mispLicenseKeyDetails[0].expiryDateTime, 'dateInWords')
+                mispLicenseKeyName: mispDetails.mispLicenseKeyName || '-',
+                mispPartnerId: mispDetails.mispPartnerId,
+                expiryDateTime: formatDate(mispDetails.expiryDateTime, 'dateInWords')
             }}
             ...
         />
     );
 }

Also applies to: 1295-1307, 1325-1327

🤖 Prompt for AI Agents
In @pmp-ui-v2/src/utils/AppUtils.js around lines 1209 - 1221, The MISP block
uses notification.notificationDetails.mispLicenseKeyDetails[0] without
validating the array; update the MISP handling (the JSX Trans usage and any
helper code that references
notification.notificationDetails.mispLicenseKeyDetails at lines ~1209, ~1295,
~1325) to first verify that notification.notificationDetails &&
Array.isArray(notification.notificationDetails.mispLicenseKeyDetails) &&
notification.notificationDetails.mispLicenseKeyDetails.length > 0, then safely
read the firstItem (e.g., const first =
notification.notificationDetails.mispLicenseKeyDetails[0]) and pass fallbacks
for first.mispLicenseKeyName, first.mispPartnerId and first.expiryDateTime into
formatDate/Trans; ensure the same defensive check/fallback logic is applied to
the other occurrences mentioned (around 1295-1307, 1325-1327).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants