-
Notifications
You must be signed in to change notification settings - Fork 21
Feat/v6 -> dev #1271
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
Feat/v6 -> dev #1271
Conversation
…corecard Fix sortOrder for scorecardQuestions & make error more visible
Fixes view and css on Restricted page
…corecard Fix error width
…corecard Fix error width
fix(PM-1503): Weight column in view scorecard page
…corecard PM-1504 - scorecard: Make category options dependent on project type
…corecard PM-1504 - redirect to view scorecard
fix(PM-1503) Used requiresUpload from backend
fix(PM-1503): removed breadcrumb for non admin users
…corecard PM-1504 edit create scorecard - sort scorecard data by sortOrder
…corecard fix scoorecard data fetch
| * @returns Escaped string safe for interpolation in a regex. | ||
| */ | ||
| export function escapeRegexLiteral(value: string): string { | ||
| return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') |
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.
[correctness]
The escapeRegexLiteral function does not handle null or undefined values, which could lead to runtime errors if such values are passed. Consider adding a check to return an empty string or throw an error if the input is not a string.
| } | ||
|
|
||
| const escapedTarget = escapeRegexLiteral(target) | ||
| .replace(/ /g, '\\ ') |
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.
[💡 maintainability]
The use of replace(/ /g, '\ ') in the regex construction could be simplified by using a single replace call with a regex that matches spaces, hyphens, and underscores. This would improve readability and maintainability.
| * @returns True when the phase name is allowed for review operations. | ||
| */ | ||
| export function isPhaseAllowedForReview(phaseName?: string | null): boolean { | ||
| const normalizedAlpha = getNormalizedAlphaLowerCase(phaseName) |
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.
[correctness]
The function isPhaseAllowedForReview returns true when normalizedAlpha is falsy, which might not be the intended behavior if phaseName is null or undefined. Consider clarifying the logic to ensure it aligns with the intended use case.
| legacyScorecardId?: string | number, | ||
| ): { scorecardId?: string; phaseIds: Set<string> } { | ||
| const normalizedPhaseName = phaseName.toLowerCase() | ||
| const phaseIds = collectPhaseIdsForName(phases, reviewers, phaseName) |
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.
[💡 performance]
The collectPhaseIdsForName function is called with phaseName as a parameter, but the function internally normalizes the phase name to lowercase. Consider passing the already normalized normalizedPhaseName to avoid redundant normalization and improve performance slightly.
| } | ||
| }) | ||
|
|
||
| const reviewMatch = reviews?.find(review => { |
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.
[maintainability]
The logic for matching reviews based on scorecardId and phaseId is complex and involves multiple checks. Consider refactoring this block into smaller functions to improve readability and maintainability.
| return { phaseIds, scorecardId: reviewerMatch.scorecardId } | ||
| } | ||
|
|
||
| const constraintValue = matchingPhases |
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.
[performance]
The use of find followed by map could be replaced with a single find that directly returns the desired value, which would improve performance by avoiding unnecessary iterations.
| if (assignmentReview) { | ||
| const existingReviewItems = reviewForResource?.reviewItems | ||
| reviewForResource = { | ||
| ...(reviewForResource ?? {}), |
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.
[correctness]
The spread operator is used to merge reviewForResource and assignmentReview. If both objects have overlapping properties, assignmentReview will overwrite those in reviewForResource. Ensure this behavior is intended and does not lead to unintended data loss.
| challengeReviewById: Map<string, BackendReview>, | ||
| ): BackendReview { | ||
| const canonicalReview = reviewForResource.id | ||
| ? challengeReviewById.get(reviewForResource.id) |
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.
[correctness]
Accessing the canonicalReview from challengeReviewById using reviewForResource.id assumes that the ID is always present and valid. Consider handling cases where the ID might be missing or invalid to prevent potential runtime errors.
| * @returns Normalized string representation of the phase identifier when present. | ||
| */ | ||
| export function resolveReviewPhaseId(review: BackendReview | undefined): string | undefined { | ||
| if (!review || review.phaseId === null || review.phaseId === undefined) { |
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.
[💡 readability]
Consider using review?.phaseId instead of checking for null and undefined separately. This can simplify the condition and improve readability.
| matchesPhase: boolean, | ||
| matchesScorecard: boolean, | ||
| ): boolean { | ||
| const matchedCriteria = [ |
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.
[💡 readability]
The use of filter(Boolean) is correct but can be slightly confusing. Consider using a more explicit approach to filter out undefined values for clarity.
| scorecardIdBeingChecked: scorecardId, | ||
| }) | ||
|
|
||
| const normalizedPhaseName = getNormalizedLowerCase(phaseName) |
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.
[correctness]
The function getNormalizedLowerCase is used multiple times on potentially undefined values. Ensure this function handles undefined inputs gracefully to avoid unexpected errors.
|
|
||
| if (typeof metadata === 'string') { | ||
| try { | ||
| const parsed = JSON.parse(metadata) |
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.
[security]
Consider specifying the reviver parameter in JSON.parse to handle potential data transformations or validations during parsing.
| return 'PASS' | ||
| } | ||
|
|
||
| if (normalized === 'fail' || normalized === 'no pass' || normalized === 'no-pass' || normalized === 'nopass') { |
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.
[maintainability]
The normalization logic for 'no pass' variations could be simplified by using a regular expression to match these patterns, improving maintainability.
| ] as const | ||
|
|
||
| const normalizeReviewPhaseHint = (value?: string | null): string => ( | ||
| typeof value === 'string' |
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.
[💡 readability]
The normalizeReviewPhaseHint function uses a regular expression to remove non-alphabetic characters. Consider adding a comment explaining the purpose of this transformation, as it may not be immediately clear to other developers.
| return undefined | ||
| } | ||
|
|
||
| const matchingPhase = phases.find(phase => { |
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.
[correctness]
The resolvePhaseNameFromId function uses both phase.id and phase.phaseId as candidates for matching. Ensure that these fields are consistently populated across all BackendPhase objects to avoid unexpected behavior.
|
|
||
| const normalizedCandidates = collectReviewHints(submission, phases) | ||
| if (!normalizedCandidates.size) { | ||
| if (process.env.NODE_ENV !== 'production') { |
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.
[❗❗ security]
The debug logging inside shouldIncludeInReviewPhase is conditioned on process.env.NODE_ENV !== 'production'. Ensure that this environment variable is correctly set in all deployment environments to avoid leaking debug information.
| return true | ||
| } | ||
|
|
||
| const normalizedCandidateList = Array.from(normalizedCandidates) |
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.
[💡 performance]
The conversion of normalizedCandidates to an array using Array.from could be avoided if Set.prototype.some is used directly. This would improve performance slightly by avoiding the creation of an intermediate array.
| metadata?: BackendReview['metadata'], | ||
| ): Screening['result'] { | ||
| if (typeof numericScore === 'number' && typeof minPass === 'number') { | ||
| return numericScore >= minPass ? 'PASS' : 'NO PASS' |
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.
[correctness]
Consider using strict equality checks (===) instead of loose equality checks (==) for comparing numeric values to ensure type safety.
| } | ||
|
|
||
| if (baseResult) { | ||
| const normalizedBase = baseResult.toUpperCase() |
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.
[correctness]
The normalization of baseResult assumes it is always a string. Consider adding a type check to ensure baseResult is a string before calling .toUpperCase() to prevent runtime errors.
| import { EnvironmentConfig } from '~/config' | ||
|
|
||
| export const DEBUG_CHECKPOINT_PHASES = Boolean( | ||
| (EnvironmentConfig as unknown as { DEBUG_CHECKPOINT_PHASES?: boolean }).DEBUG_CHECKPOINT_PHASES, |
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.
[correctness]
Casting EnvironmentConfig to unknown and then to a specific type can lead to runtime errors if EnvironmentConfig does not match the expected shape. Consider adding runtime checks or using a safer approach to access DEBUG_CHECKPOINT_PHASES.
| } | ||
|
|
||
| const globalTarget = globalThis as Record<string, unknown> | ||
| globalTarget[CHECKPOINT_DEBUG_EXPORT_KEY] = [...checkpointDebugEntries] |
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.
[maintainability]
Exporting logs to the global scope can lead to potential memory leaks or unintended side effects if not managed properly. Consider implementing a mechanism to clear or manage these logs periodically.
| return | ||
| } | ||
|
|
||
| checkpointDebugEntries.push({ level, namespace, payload }) |
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.
[performance]
The checkpointDebugEntries array can grow indefinitely if DEBUG_CHECKPOINT_PHASES is true, potentially leading to memory issues. Ensure that the array size is controlled, as done with MAX_CHECKPOINT_DEBUG_ENTRIES, but also consider the implications of frequently shifting elements.
| matchingSubmission, | ||
| review, | ||
| }: SubmissionIdResolutionArgs): string | undefined { | ||
| return review.submissionId |
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.
[correctness]
The precedence order for resolving submission IDs could lead to unexpected results if review.submissionId is present but invalid. Consider validating review.submissionId before using it as the resolved ID.
| baseSubmissionInfo, | ||
| matchingSubmission, | ||
| }: SubmitterMemberIdResolutionArgs): string { | ||
| return matchingSubmission?.memberId ?? baseSubmissionInfo?.memberId ?? '' |
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.
[correctness]
Returning an empty string for the submitter member ID might lead to confusion or errors downstream if consumers of this function expect a valid member ID. Consider returning undefined instead to clearly indicate the absence of a member ID.
| const escapedTarget = escapeRegexLiteral(target) | ||
| .replace(/ /g, '\\ ') |
Check failure
Code scanning / CodeQL
Incomplete string escaping or encoding High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 2 days ago
To ensure all meta-characters are properly escaped for safe use in a RegExp, and to avoid edge cases where a backslash followed by a space or other meta-character could slip through, the best fix is as follows:
- Refactor the regex escaping logic so that any transformations (e.g., replacements of spaces with regex patterns) are performed before escaping meta-characters, or combine them in one pass.
- Consider using a trusted library for RegExp escaping, such as
escape-string-regexp, but if unavailable, ensure our function covers all edge cases, including backslashes, and is never applied on a string that has already been manipulated. - In this file, update the code at and near line 115 so that the string is first transformed (spaces to intended regex) and then fully escaped, or use a tailored escape-for-regexp function for word-boundary matching.
- No new methods are needed, but the code constructing the boundary regex should be restructured: first, replace spaces in the target with
[-_\\s]+, then escape meta-characters, then interpolate inside the RegExp.
-
Copy modified lines R115-R117
| @@ -112,9 +112,9 @@ | ||
| return { source: 'stringExact' } | ||
| } | ||
|
|
||
| const escapedTarget = escapeRegexLiteral(target) | ||
| .replace(/ /g, '\\ ') | ||
| const sepInsensitive = new RegExp(`\\b${escapedTarget.replace(/\\ /g, '[-_\\s]+')}\\b`) | ||
| // Replace space characters with a separator regex, then escape the whole for use in RegExp | ||
| const sepInsensitiveStr = escapeRegexLiteral(target.replace(/ /g, '[-_\\s]+')); | ||
| const sepInsensitive = new RegExp(`\\b${sepInsensitiveStr}\\b`); | ||
| if (sepInsensitive.test(normalizedMetadata)) { | ||
| return { source: 'stringBoundary' } | ||
| } |
| ) | ||
| const approvalRows: SubmissionInfo[] = useMemo( | ||
| () => { | ||
| if (!props.reviews.length) { |
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.
[correctness]
The check if (!props.reviews.length) assumes props.reviews is always defined. Consider adding a nullish coalescing operator to ensure safety: if (!(props.reviews ?? []).length).
| const isSubmitterView = actionChallengeRole === SUBMITTER | ||
| const sourceRows = isSubmitterView ? props.submitterReviews : props.reviews | ||
| const myMemberIds = useMemo<Set<string>>( | ||
| () => new Set((myResources ?? []).map(resource => resource.memberId)), |
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.
[💡 performance]
Using useMemo for myMemberIds is beneficial for performance, but ensure that myResources is not frequently changing. If it changes often, the memoization might not provide significant benefits.
| }, | ||
| [challengeInfo?.status], | ||
| ) | ||
| const hasPassedPostMortemThreshold = useMemo( |
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.
[💡 performance]
The useMemo hook for hasPassedPostMortemThreshold is appropriate here to avoid unnecessary recalculations. However, ensure that the sourceRows and myMemberIds dependencies are stable and do not change frequently, as this could negate the performance benefits.
| const filteredScreening = useMemo<Screening[]>( | ||
| () => { | ||
| const baseRows = props.screening ?? [] | ||
| const canSeeAll = isPrivilegedRole || hasReviewerRole |
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.
[maintainability]
The variable canSeeAll is defined but not used in the first if condition. Consider using canSeeAll consistently to improve readability and maintainability.
|
|
||
| return baseRows.filter(row => { | ||
| if (row.myReviewResourceId | ||
| && (screenerResourceIds.has(row.myReviewResourceId) |
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.
[correctness]
The condition checks if row.myReviewResourceId is in either screenerResourceIds or reviewerResourceIds. Ensure that both sets are correctly populated and managed to avoid potential access issues.
| }, []) | ||
|
|
||
| const openHistoryModalForKey = useCallback( | ||
| (memberId: string | undefined, submissionId: string): void => { |
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.
[correctness]
The openHistoryModalForKey function does not handle the case where memberId is undefined and submissionId is also undefined. Consider adding a check to ensure submissionId is always defined before proceeding.
| ) | ||
|
|
||
| const getHistoryRestriction = useCallback( | ||
| (submission: SubmissionInfo) => { |
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.
[correctness]
The getHistoryRestriction function assumes that submission.memberId is always defined when checking for restrictions. Consider handling the case where memberId might be undefined to avoid potential runtime errors.
| type='button' | ||
| className={styles.historyButton} | ||
| data-submission-id={submission.id} | ||
| data-member-id={submission.memberId ?? ''} |
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.
[💡 correctness]
The data-member-id attribute is set to an empty string when submission.memberId is undefined. This could lead to unexpected behavior if the attribute is used elsewhere. Consider omitting the attribute if memberId is not available.
|
|
||
| const isInProgressStatus = (value: string | undefined): boolean => ( | ||
| typeof value === 'string' | ||
| && value.trim() |
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.
[💡 readability]
Consider using value.trim().toUpperCase() === 'IN_PROGRESS' directly in the return statement for better readability and to avoid unnecessary line breaks.
| ) | ||
|
|
||
| const isReviewRowInProgress = (entry: Screening): boolean => ( | ||
| isInProgressStatus(entry.reviewStatus) |
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.
[correctness]
The function isReviewRowInProgress checks both reviewStatus and myReviewStatus. Ensure that this logic is intentional and that both statuses need to be checked for the same condition.
| label: 'Screening Result', | ||
| propertyName: 'result', | ||
| renderer: (data: Screening) => { | ||
| if (isReviewRowInProgress(data)) { |
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.
[💡 readability]
Returning a hyphen (<span>-</span>) when the review row is in progress might not be informative. Consider providing a more descriptive placeholder or message to indicate the status.
| const isOwnedSubmission = data.memberId | ||
| ? ownedMemberIds.has(data.memberId) | ||
| : false | ||
| const canAccessReview = !isSubmitterView |
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.
[💡 style]
The condition Boolean(props.isChallengeCompleted && props.hasPassedThreshold) could be simplified to props.isChallengeCompleted && props.hasPassedThreshold since the && operator already returns a boolean value.
|
|
||
| const isInProgressStatus = (value: string | undefined): boolean => ( | ||
| typeof value === 'string' | ||
| && value.trim() |
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.
[💡 correctness]
Consider using localeCompare for case-insensitive string comparison to handle edge cases with different locales.
| label: 'Screening Result', | ||
| propertyName: 'result', | ||
| renderer: (data: Screening) => { | ||
| if (isScreeningReviewInProgress(data)) { |
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.
[💡 readability]
Returning a simple span with a dash for in-progress status might be misleading. Consider using a more descriptive placeholder or tooltip to indicate the status is in progress.
| defaultMinimumPassingScore, | ||
| }: ResolveSubmissionReviewResultOptions = options | ||
|
|
||
| if (hasInProgressReviewStatus(submission)) { |
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.
[correctness]
The early return when hasInProgressReviewStatus(submission) is true could lead to unexpected behavior if the function is expected to handle other statuses as well. Ensure that this logic aligns with the intended business rules.
| return 'FAIL' | ||
| } | ||
|
|
||
| if (scoreOutcome === 'FAIL' && metadataOutcome === 'PASS') { |
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.
[correctness]
The condition scoreOutcome === 'FAIL' && metadataOutcome === 'PASS' returning 'PASS' might be counterintuitive. Verify that this logic is intended and aligns with the business requirements.
| // Current viewer's resource ids that grant Screening review access (Screener or Reviewer) | ||
| const myScreeningReviewerResourceIds = new Set<string>(); | ||
| (myResources ?? []).forEach(resource => { | ||
| const normalizedRoleName = (resource.roleName || '').toLowerCase() |
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.
[correctness]
The use of toLowerCase() on normalizedRoleName assumes that all role names are in a case-insensitive format. If role names are case-sensitive, this could lead to incorrect role matching. Consider verifying the case sensitivity of role names in the system.
|
|
||
| const matchesScreenerRole = normalizedRoleName.includes('screener') | ||
| && !normalizedRoleName.includes('checkpoint') | ||
| const matchesReviewerRole = normalizedRoleName.replace(/[^a-z]/g, '') === 'reviewer' |
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.
[correctness]
The regular expression replace(/[^a-z]/g, '') assumes that role names contain only alphabetic characters. If role names can contain numbers or special characters, this could lead to incorrect role matching. Consider revising the logic to handle such cases.
| const sorted = orderBy( | ||
| reviews, | ||
| [ | ||
| (review: BackendReview) => Boolean(review.committed), |
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.
[correctness]
The use of orderBy with a default value of -Infinity for scores could lead to unexpected behavior if getNumericScore returns non-numeric values. Consider adding validation to ensure that scores are numeric before sorting.
| return typeof score === 'number' ? score : -Infinity | ||
| }, | ||
| (review: BackendReview) => { | ||
| const updatedAt = review.updatedAt || review.reviewDate || review.createdAt |
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.
[correctness]
The logic for determining the updatedAt date uses Date.parse, which can behave inconsistently across different browsers and environments. Consider using a more robust date parsing library to ensure consistent behavior.
| return | ||
| } | ||
|
|
||
| const resourceIdValue = resource.id |
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.
[💡 maintainability]
The logic for determining resourceId involves multiple type checks and conversions. Consider refactoring this logic into a utility function to improve readability and maintainability.
| const { actionChallengeRole, hasReviewerRole }: useRoleProps = useRole() | ||
|
|
||
| const reviewContextRole = useMemo( | ||
| () => getRoleForContext('review', { actionChallengeRole, hasReviewerRole }), |
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.
[correctness]
The getRoleForContext function is used to determine reviewContextRole, but it's unclear if this function handles all possible role combinations correctly. Ensure that getRoleForContext is well-tested to avoid potential logic errors in role determination.
| .filter(resource => { | ||
| const normalizedRoleName = resource.roleName | ||
| ?.toLowerCase() | ||
| .replace(/[^a-z]/g, '') ?? '' |
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.
[correctness]
The use of replace(/[^a-z]/g, '') to normalize the role name could potentially strip out important characters if the role names are expected to contain non-alphabetic characters. Consider whether this is the intended behavior or if a more specific normalization is needed.
| context: string | undefined, | ||
| { actionChallengeRole, hasReviewerRole }: ContextRoleSource, | ||
| ): ChallengeRole => { | ||
| if (context?.toLowerCase() === 'review' && hasReviewerRole) { |
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.
[correctness]
The check context?.toLowerCase() === 'review' assumes that the context string will always be in a format that can be converted to lowercase and compared directly. Consider adding validation or handling for unexpected context values to prevent potential issues.
|
|
||
| const { | ||
| actionChallengeRole, | ||
| hasReviewerRole, |
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.
[performance]
The hasReviewerRole variable is now being destructured from useRole(). Ensure that useRole() correctly provides this value, as it was previously computed using useMemo. This change could impact performance if useRole() does not memoize the result.
| ), | ||
| 'checkpoint review': normalizedRoleName => normalizedRoleName === 'checkpointreviewer', | ||
| 'checkpoint screening': normalizedRoleName => normalizedRoleName === 'checkpointscreener', | ||
| 'post-mortem': normalizedRoleName => normalizedRoleName.includes('postmortem'), |
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.
[❗❗ correctness]
The normalization of role names in PHASE_ROLE_MATCHERS has changed to remove spaces (e.g., 'checkpoint screener' to 'checkpointscreener'). Ensure that this change is intentional and that all relevant parts of the application are updated to match this new format.
|
|
||
| type RoleMatcher = (normalizedRoleName: string) => boolean | ||
|
|
||
| const normalizeRoleName = (value: unknown): string => { |
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.
[correctness]
The normalizeRoleName function replaces all non-alphabetic characters with an empty string. This could lead to unexpected behavior if role names contain numbers or special characters that are significant. Consider whether this normalization is too aggressive and if it might inadvertently alter valid role names.
Related JIRA Ticket:
https://topcoder.atlassian.net/browse/
What's in this PR?
Moving V6 stuff to dev env to prepare the switch off "-v6" .