Skip to content

Comments

PM-3851 ai review configuration#1733

Open
vas3a wants to merge 16 commits intodevelopfrom
PM-3851_ai-review-configuration
Open

PM-3851 ai review configuration#1733
vas3a wants to merge 16 commits intodevelopfrom
PM-3851_ai-review-configuration

Conversation

@vas3a
Copy link
Collaborator

@vas3a vas3a commented Feb 23, 2026

https://topcoder.atlassian.net/browse/PM-3851 - Work Manager UI — AI Review Configuration

Note: we need to add TC_REVIEWS_API_BASE_URL to env (just needs to point to "https://api.topocoder-dev.com/v6"

image image image image image localhost_3001_projects_100450_challenges_97701509-f4ee-4a03-9bd1-bad7413d2274_edit localhost_3001_projects_100450_challenges_97701509-f4ee-4a03-9bd1-bad7413d2274_edit (1)

@vas3a vas3a requested review from jmgasper and kkartunov February 23, 2026 09:57
<div className={styles.summaryCard}>
<h4>Workflows</h4>
<div className={styles.summaryValue}>
{configuration.workflows.length} total

Choose a reason for hiding this comment

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

[⚠️ correctness]
Consider handling the case where configuration.workflows might be undefined or null to prevent potential runtime errors. You could use optional chaining or a default value.

{configuration.workflows.length} total
{configuration.workflows.some(w => w.isGating) && (
<div className={styles.summarySubtext}>
{configuration.workflows.filter(w => w.isGating).length} gating

Choose a reason for hiding this comment

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

[💡 performance]
The use of filter here could be optimized by using reduce to count the gating workflows in a single pass, which might improve performance slightly if the list is large.

const WeightValidationCard = ({ workflows }) => {
const scoringWorkflows = workflows.filter(workflow => !workflow.isGating)
const gatingWorkflows = workflows.filter(workflow => workflow.isGating)
const weightsTotal = workflows.reduce((sum, workflow) => sum + (Number(workflow.weightPercent) || 0), 0)

Choose a reason for hiding this comment

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

[⚠️ correctness]
Consider using parseFloat instead of Number for parsing weightPercent to ensure that decimal values are correctly handled. Number can sometimes lead to unexpected results with non-numeric strings.

const scoringWorkflows = workflows.filter(workflow => !workflow.isGating)
const gatingWorkflows = workflows.filter(workflow => workflow.isGating)
const weightsTotal = workflows.reduce((sum, workflow) => sum + (Number(workflow.weightPercent) || 0), 0)
const isWeightValid = Math.abs(weightsTotal - 100) < 0.01

Choose a reason for hiding this comment

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

[⚠️ correctness]
The weight validation logic using Math.abs(weightsTotal - 100) < 0.01 might lead to unexpected results due to floating-point precision issues. Consider using a more robust method to handle floating-point comparisons.

const gatingWorkflows = workflows.filter(workflow => workflow.isGating)
const weightsTotal = workflows.reduce((sum, workflow) => sum + (Number(workflow.weightPercent) || 0), 0)
const isWeightValid = Math.abs(weightsTotal - 100) < 0.01
const remainingWeight = Math.round((100 - weightsTotal) * 100) / 100

Choose a reason for hiding this comment

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

[💡 correctness]
Rounding remainingWeight using Math.round might not be necessary if the intention is to maintain precision for display purposes. Consider whether this rounding is required or if it could lead to misleading information.

}
}
} catch (err) {
console.error('Error loading AI review configuration:', err)

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Consider handling the error more gracefully by providing user feedback or retrying the operation. Currently, the error is only logged to the console, which may not be sufficient for user-facing applications.

lastSavedConfigRef.current = savedConfig
} catch (error) {
console.error('Error autosaving AI review configuration:', error)
toastFailure(`⚠️ Autosave error: ${error.message}`)

Choose a reason for hiding this comment

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

[❗❗ security]
The error message displayed to the user includes the raw error message, which might expose sensitive information. Consider providing a more user-friendly error message.

}

loadAIReviewConfig()
}, [challengeId, updateConfiguration])

Choose a reason for hiding this comment

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

[💡 performance]
The updateConfiguration function is included in the dependency array of the useEffect, but it is not used within the effect. This could lead to unnecessary re-renders. Consider removing it from the dependency array.

setTemplates(fetchedTemplates || [])
setTemplatesLoading(false)
} catch (err) {
console.error('Error loading templates:', err)

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Consider using a more descriptive error message or including the error details in the setError call to provide more context to the user or developer when debugging.

@@ -0,0 +1,6 @@
export const isAIReviewer = (reviewer) => {
return reviewer && (
(reviewer.aiWorkflowId && reviewer.aiWorkflowId.trim() !== '') ||

Choose a reason for hiding this comment

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

[⚠️ correctness]
Consider using String.prototype.trim() only after verifying that reviewer.aiWorkflowId is a string to avoid potential runtime errors if aiWorkflowId is not a string.

(reviewer.aiWorkflowId && reviewer.aiWorkflowId.trim() !== '') ||
(reviewer.isMemberReview === false)
)
} No newline at end of file

Choose a reason for hiding this comment

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

[💡 style]
Add a newline at the end of the file to adhere to POSIX standards and improve compatibility with various tools.

aiReviewers,
}) => {
const { workflows = [] } = metadata
const assignedWorkflows = useMemo(() => aiReviewers.map(reviewer => {

Choose a reason for hiding this comment

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

[💡 performance]
Using useMemo here might not be necessary unless aiReviewers or workflows are large arrays or the computation is expensive. Consider removing it if performance is not a concern, as it adds complexity.

<div className={styles.workflowsList}>
{assignedWorkflows.map((item, index) => (
<AIWorkflowCard
key={`workflow-${index}`}

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Using the index as a key in a list can lead to issues if the list is reordered or modified. Consider using a unique identifier from the item object, such as item.reviewer.aiWorkflowId, if available.

<AIWorkflowCard
key={`workflow-${index}`}
workflow={item.workflow || { name: item.reviewer.aiWorkflowId }}
scorecardId={(item.workflow || item.reviewer).scorecardId}

Choose a reason for hiding this comment

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

[⚠️ correctness]
Accessing scorecardId from (item.workflow || item.reviewer) assumes that one of these objects will always have a scorecardId. Ensure that this assumption holds true in all cases to avoid potential runtime errors.

if (error.response && error.response.status === 404) {
return null
}
console.error(`Error fetching AI review config for challenge %s:`, challengeId, error.message)

Choose a reason for hiding this comment

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

[❗❗ correctness]
The use of %s in the console.error statement is incorrect for JavaScript. JavaScript's console.error does not support format specifiers like %s. Instead, you can pass multiple arguments to console.error, which will be concatenated with spaces. Consider removing %s and directly passing challengeId and error.message as separate arguments.

Copy link
Contributor

@kkartunov kkartunov left a comment

Choose a reason for hiding this comment

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

Awesome work

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants