-
Notifications
You must be signed in to change notification settings - Fork 67
MOSIP-43982: Moving develop code to release branch for 1.3.0-beta.4 #1599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release-1.3.x
Are you sure you want to change the base?
Conversation
WalkthroughThis 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
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
2adb5e8 to
22a27a8
Compare
mayuradesh
left a comment
There was a problem hiding this 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
c9bf208 to
2f40fee
Compare
Signed-off-by: sudeep j <[email protected]>
Signed-off-by: sudeep j <[email protected]>
Signed-off-by: sudeep j <[email protected]>
Signed-off-by: sudeep j <[email protected]>
Signed-off-by: sudeep j <[email protected]>
0233574 to
cfea21e
Compare
|
@coderabbitai review this PR |
|
@mayuradesh: I'll review the changes in this PR for you. ✅ Actions performedReview triggered.
|
There was a problem hiding this 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: WrapsessionStorage.setItemin try-catch to prevent navigation blocking on quota exceededIf storage is unavailable or quota exceeded,
setItemcan throw and prevent the details page from opening. The proposed fix is appropriate.The secondary concern is already addressed—the details page (
ViewAdminDeviceDetails.jsline 21) correctly reads fromsessionStorage, notlocalStorage.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 toYand acceptingY/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 $NSon line 14 executes beforeset -eprotection (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-developchart version formosip/uitestrigrequires manual verification in the external Helm repo, as does the docker image tag formosipqa/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. Thekubectl create nscommand 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-developis defined athelm/pmp-ui-v2/Chart.yaml:5and is published to the configured Helm repository (https://mosip.github.io).helm/pmp-ui-v2/values.yaml (1)
52-62: Clarify versioning intent for1.3.xtag—chart is marked-developin Chart.yaml.The values.yaml specifies a floating tag
1.3.xwithpullPolicy: Always, which means each restart may pull a different build. While this is acceptable for development releases (Chart.yaml showsversion: 1.3.0-develop), clarify whether this is intentional. If graduating to a stable release, pin a concrete tag (e.g.,1.3.0or1.3.0-beta.4) for reproducible deployments and clear traceability.helm/pmp-ui-v2/Chart.yaml (1)
1-6: Clarify Chart.yaml versioning semantics for1.3.0-develop.The
-developsuffix 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-developconvention in your release process.Also note:
appVersionis 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 ofisPolicyManager.🔧 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, usingroles?.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.errshould beconsole.error.
console.erris not a valid console method and will throw a runtime error. This should beconsole.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.isCaSignedPartnerCertificateAvailableis 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: HardenitemsPerPageinitialization (avoidNaN/SSR issues)Right now
Number(sessionStorage.getItem('itemsPerPage'))can becomeNaNand flow into pagination, and directsessionStorageaccess 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 renamingpartnerDatatopolicyDatafor clarity.The variable
partnerDatastores policy attributes, which could be confusing. Renaming it topolicyDataorpolicyAttributesDatawould 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.removeItemsuggests 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_PARTNERandABIS_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_typeuses 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 usingselect_policy_popup_partner_typefor 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 componentAlso 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
fetchPartnerListto 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
partnerIdDropdownDataremains 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 usemx-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 withgetLanguageLabel.
getLanguageDisplayNameduplicates the language map fromgetLanguageLabel(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 invalidateOidcEntryText.The function mutates the
errorsobject viasetErrors, but the logic for determining which error to show is complex. The condition on line 1595 checksentry.text.trim() === '' && entry.text !== ''which only matches whitespace-only strings.pmp-ui-v2/src/pages/admin/authenticationServices/AdminApiKeysList.js (1)
186-193: Unusedindexparameter ineditExpiryDate.The
indexparameter 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
selectedDateStrto 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 requiresselectedDateStr !== 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 incheckAdditionalConfigSupport.The
if (isRequired)check on line 81 is redundant sincesetAdditionalConfigRequired(isRequired)could simply be called unconditionally. If the intent is to avoid unnecessary state updates whenisRequiredisfalse, 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:tabIndexshould be numeric; consideraria-expanded/aria-controls.React expects
tabIndex={0}(not a string). Also, for better a11y, wirearia-expandedandaria-controlsbetween 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 onisLoginLanguageRTL.
349-413: PropTypes: error strings likely shouldn’t beisRequired.
consentExpiryError,purposeTitleDefaultError,purposeSubtitleDefaultErrorcommonly represent “no error” as""/undefined. If callers ever passundefined, currentisRequiredwill 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: SetadditionalConfigRequireddirectly 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 movingisSelectPolicyPopupVisible/isUserConsentGiventouseRef(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
| image: | ||
| registry: docker.io | ||
| repository: mosipid/uitest-pmp-v2 | ||
| tag: 1.3.0-beta.3 | ||
| repository: mosipqa/uitest-pmp-v2 | ||
| tag: 1.3.x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's explore the repository structure to understand the deployment strategy
git ls-files | head -20Repository: 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 -20Repository: 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 -30Repository: 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 -10Repository: 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.mdRepository: mosip/partner-management-portal
Length of output: 851
🏁 Script executed:
# Check the main README for context about release strategy
cat README.md | head -50Repository: mosip/partner-management-portal
Length of output: 773
🏁 Script executed:
# Check the helm chart README for deployment guidance
cat helm/pmp-ui-v2/README.mdRepository: 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.yamlRepository: mosip/partner-management-portal
Length of output: 12725
🏁 Script executed:
# Check the Chart.yaml to understand chart versioning
cat helm/pmp-ui-v2/Chart.yamlRepository: 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.
| "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 لا يدعمها." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| "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." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| "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.
| 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; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| 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); | ||
| }, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| 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(""); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| <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> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate DOM id + unstable React keys in the multi-language section.
id="add_client_name_lang_map_entry"is used twice.key={index}should bekey={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).
| {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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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 -C2Repository: 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*[:=]" -C3Repository: 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.jsRepository: 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.jsRepository: 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 -20Repository: 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.
| if (!isAdminPath) { | ||
| setPartnerType(getPartnerTypeDescription(selectedPartner.partnerType, t)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| } 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`} /> }} | ||
| /> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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).
Summary by CodeRabbit
Release Notes
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.