Conversation
…nt List Initial Commit
…ta-model-in-the-Payment-List
Unit test fixing
Exception handling update
…e-Tagging-data-model-in-the-Payment-List Feature/ab#29103 restructuring the tagging data model in the payment list
…anagement-permissions
Feature/ab#29310 add paygroup to site
- Add the ApplicantName property to ApplicantSummaryViewModel and updates the Default.cshtml view to display and bind this new field. - Adjusts the layout to show Applicant Id, ApplicantName and RedStop in a row
…gnKey feature/AB#29103-AddInDrop-DropFK for app tage
…zation-migration bugfix/AB#29103 - Tag Model Normalization Migration Scripts
…anagement-permissions
…erfacee and Services
…me-ApplicantInfoTab feature/AB#29464 Add ApplicantName to Applicant Info Tab
…ermissions feature/AB#29096 - Add Tag Management Permissions for Create Tag
…-instances AB#29451 add fix endpoint to recover missing worksheet instances
There was a problem hiding this comment.
Pull Request Overview
This PR implements a comprehensive tag restructuring system to replace the previous comma-separated tag approach with a centralized Tag entity and proper relationships. The key changes include introducing a global Tag entity, refactoring tag management across both applications and payments, and implementing normalized tag relationships.
- Introduces centralized Tag entity with proper foreign key relationships
- Migrates from comma-separated string tags to normalized tag relationships
- Updates tag management UI with CRUD operations and proper tag selection
Reviewed Changes
Copilot reviewed 85 out of 87 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| ApplicationTagWidgetTests.cs | Updated test to use new TagDto structure instead of Text property |
| ApplicationTagsAppServiceTests.cs | Refactored tests to work with new tag assignment model using TagDto objects |
| ApplicationTagsWidgetViewComponent.cs | Modified to access tag name through Tag.Name navigation property |
| Default.cshtml (ApplicantInfo) | Restructured form layout moving ApplicantName and RedStop fields |
| ApplicantSummaryViewModel.cs | Added ApplicantName property to view model |
| Default.js (ActionBar) | Updated JavaScript to handle JSON tag objects instead of comma-separated strings |
| TagManagement files | Complete overhaul of tag management with new create/edit modals and permissions |
| Entity/Repository files | Database schema changes with new Tag entity and foreign key relationships |
| Migration file | Complex migration to normalize existing comma-separated tags into new structure |
Comments suppressed due to low confidence (1)
applications/Unity.GrantManager/src/Unity.GrantManager.Application/Tags/TagsAppService.cs:67
- The error message should be more descriptive than just re-throwing the original exception message. Consider providing context about the tag rename operation that failed.
{
| EFT = 1, | ||
| Cheque = 2, | ||
| GLP = 3 | ||
| Cheque = 2 |
There was a problem hiding this comment.
The removal of the GLP = 3 enum value could be a breaking change if this enum is used elsewhere in the codebase. Consider using the Obsolete attribute instead of completely removing it to maintain backward compatibility.
| return; | ||
|
|
||
| this.arr.push(tagText); | ||
| this.arr.push({ Id: id, Name: tagText }); |
There was a problem hiding this comment.
The addTag method should validate that the 'id' parameter is not null or empty before pushing to the array, as this could cause issues with tag identification later.
| } | ||
| catch (Exception ex) | ||
| { | ||
| Console.WriteLine($"Error processing ApplicationId {item}: {ex.Message}"); |
There was a problem hiding this comment.
Using Console.WriteLine for error logging is not appropriate in production code. Use the injected Logger instead for proper error handling and monitoring.
| INSERT INTO ""ApplicationTags"" ( | ||
| ""Id"", ""ApplicationId"", ""TenantId"", ""TagId"", ""Text"", ""ExtraProperties"", ""ConcurrencyStamp"", ""CreationTime"", ""CreatorId"", ""LastModificationTime"", ""LastModifierId"" | ||
| ) | ||
| SELECT | ||
| gen_random_uuid(), | ||
| f.""ApplicationId"", | ||
| f.""TenantId"", | ||
| t.""Id"", | ||
| f.""TagName"", | ||
| f.""ExtraProperties"", | ||
| f.""ConcurrencyStamp"", | ||
| f.""CreationTime"", | ||
| f.""CreatorId"", | ||
| f.""LastModificationTime"", | ||
| f.""LastModifierId"" | ||
| FROM flattened f | ||
| JOIN ""Tags"" t | ||
| ON t.""TenantId"" IS NOT DISTINCT FROM f.""TenantId"" | ||
| AND t.""Name"" = f.""TagName""; | ||
| "); | ||
|
|
||
| // 4. Remove old (unnormalized) rows | ||
| migrationBuilder.Sql(@"DELETE FROM ""Payments"".""PaymentTags"" WHERE POSITION(',' IN ""Text"") > 0;"); | ||
| migrationBuilder.Sql(@"DELETE FROM ""ApplicationTags"" WHERE POSITION(',' IN ""Text"") > 0;"); |
There was a problem hiding this comment.
The migration deletes rows based on comma presence in Text field, but this could potentially delete valid single tags that contain commas as part of their content. Consider a more precise approach to identify which rows were created by the normalization process.
| INSERT INTO ""ApplicationTags"" ( | |
| ""Id"", ""ApplicationId"", ""TenantId"", ""TagId"", ""Text"", ""ExtraProperties"", ""ConcurrencyStamp"", ""CreationTime"", ""CreatorId"", ""LastModificationTime"", ""LastModifierId"" | |
| ) | |
| SELECT | |
| gen_random_uuid(), | |
| f.""ApplicationId"", | |
| f.""TenantId"", | |
| t.""Id"", | |
| f.""TagName"", | |
| f.""ExtraProperties"", | |
| f.""ConcurrencyStamp"", | |
| f.""CreationTime"", | |
| f.""CreatorId"", | |
| f.""LastModificationTime"", | |
| f.""LastModifierId"" | |
| FROM flattened f | |
| JOIN ""Tags"" t | |
| ON t.""TenantId"" IS NOT DISTINCT FROM f.""TenantId"" | |
| AND t.""Name"" = f.""TagName""; | |
| "); | |
| // 4. Remove old (unnormalized) rows | |
| migrationBuilder.Sql(@"DELETE FROM ""Payments"".""PaymentTags"" WHERE POSITION(',' IN ""Text"") > 0;"); | |
| migrationBuilder.Sql(@"DELETE FROM ""ApplicationTags"" WHERE POSITION(',' IN ""Text"") > 0;"); | |
| INSERT INTO ""ApplicationTags"" ( | |
| ""Id"", ""ApplicationId"", ""TenantId"", ""TagId"", ""Text"", ""ExtraProperties"", ""ConcurrencyStamp"", ""CreationTime"", ""CreatorId"", ""LastModificationTime"", ""LastModifierId"", ""IsNormalized"" | |
| ) | |
| SELECT | |
| gen_random_uuid(), | |
| f.""ApplicationId"", | |
| f.""TenantId"", | |
| t.""Id"", | |
| f.""TagName"", | |
| f.""ExtraProperties"", | |
| f.""ConcurrencyStamp"", | |
| f.""CreationTime"", | |
| f.""CreatorId"", | |
| f.""LastModificationTime"", | |
| f.""LastModifierId"", | |
| TRUE | |
| FROM flattened f | |
| JOIN ""Tags"" t | |
| ON t.""TenantId"" IS NOT DISTINCT FROM f.""TenantId"" | |
| AND t.""Name"" = f.""TagName""; | |
| "); | |
| // 4. Remove old (unnormalized) rows | |
| migrationBuilder.Sql(@"DELETE FROM ""Payments"".""PaymentTags"" WHERE ""IsNormalized"" = TRUE;"); | |
| migrationBuilder.Sql(@"DELETE FROM ""ApplicationTags"" WHERE ""IsNormalized"" = TRUE;"); |
| if (uncommonTags && uncommonTags != null) { | ||
| tagInputArray.push({ text: 'Uncommon Tags', class: 'tags-uncommon', id: 0 }) | ||
| if (uncommonTags && uncommonTags.length != 0) { | ||
| tagInputArray.push({ tagId: '00000000-0000-0000-0000-000000000000', Name: 'Uncommon Tags', class: 'tags-uncommon', Id: '00000000-0000-0000-0000-000000000000' }) |
There was a problem hiding this comment.
The hardcoded GUID '00000000-0000-0000-0000-000000000000' should be defined as a constant rather than repeated throughout the code. This magic value appears multiple times and should be centralized.
| tagInputArray.push({ tagId: '00000000-0000-0000-0000-000000000000', Name: 'Uncommon Tags', class: 'tags-uncommon', Id: '00000000-0000-0000-0000-000000000000' }) | |
| tagInputArray.push({ tagId: EMPTY_GUID, Name: 'Uncommon Tags', class: 'tags-uncommon', Id: EMPTY_GUID }) |
No description provided.