Skip to content

Feature/ab#32632 worksheet merge dev#2345

Merged
JamesPasta merged 16 commits into
devfrom
feature/AB#32632-WorksheetMergeDev
Apr 27, 2026
Merged

Feature/ab#32632 worksheet merge dev#2345
JamesPasta merged 16 commits into
devfrom
feature/AB#32632-WorksheetMergeDev

Conversation

@JamesPasta
Copy link
Copy Markdown
Collaborator

No description provided.

@github-actions
Copy link
Copy Markdown

🧪 Unit Test Results (Parallel Execution)

Tests

📊 Summary

Result Count
✅ Passed 621
❌ Failed 0
⚠️ Skipped 0

📄 HTML Reports

  • Merged Tests (HTML): Included in artifacts
    Generated automatically by CI.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the Unity Flex worksheet configuration and rendering pipeline by introducing worksheet archiving, section-level layout metadata (field width), and richer custom-field presentation options (label positioning, placeholders, etc.), with accompanying UI updates across the worksheet configuration screens and widgets.

Changes:

  • Added worksheet archiving support (DB column + UI actions) and archived-aware UI behavior.
  • Introduced WorksheetSection.Definition (jsonb) to store section layout metadata (e.g., field width) and render it in worksheet instances.
  • Refactored worksheet instance rendering into a shared partial and expanded custom-field display attributes (label position, hide label, disabled, placeholder, styles).

Reviewed changes

Copilot reviewed 42 out of 44 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs Updates EF snapshot for worksheet archiving + section definition jsonb.
applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260414100000_AddIsArchivedToWorksheets.cs Adds IsArchived column to Flex.Worksheets.
applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260413153147_AddDefinitionToWorksheetSections.cs Adds Definition jsonb column to Flex.WorksheetSections.
applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260413153147_AddDefinitionToWorksheetSections.Designer.cs Generated migration designer snapshot reflecting schema changes.
applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/fluentui-icons.css Adds a folder icon class used for archive UI affordances.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetWidget/WorksheetWidget.cs Ensures new modal JS is included in the widget bundle.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetWidget/Worksheet.js Adds archive/unarchive behavior and adjusts modal configuration.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetWidget/Worksheet.css Adds styling for section collapse toggles in worksheet configuration UI.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetWidget/Default.cshtml Adds archive/unarchive buttons and disables editing actions for archived worksheets.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetListWidget/WorksheetListWidget.cs Adds WorksheetInstance widget styles to support preview rendering.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetListWidget/WorksheetList.js Updates worksheet list interactions, sorting behavior, and preview refresh handling.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetListWidget/WorksheetList.css Adds visual styling for archived worksheets in the accordion list.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetListWidget/Default.cshtml Marks archived worksheets in the list and exposes data-is-archived to JS filters.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetInstanceWidget/_WorksheetSections.cshtml New shared partial for section + field rendering (collapse, label position, width, etc.).
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetInstanceWidget/WorksheetInstanceWidget.cs Maps section FieldWidth into the instance view model.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetInstanceWidget/ViewModels/WorksheetSectionViewModel.cs Adds FieldWidth to section view model.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetInstanceWidget/ViewModels/WorksheetSectionRenderModel.cs New render model for the shared sections partial.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetInstanceWidget/Default.css Adds CSS for label-left vs label-top layouts and collapsible section headers.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/WorksheetInstanceWidget/Default.cshtml Refactors rendering to use _WorksheetSections partial for single/multi worksheet cases.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/TextAreaWidget/Default.cshtml Reuses parsed definition and adds placeholder support.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/DefaultFieldWidget/DefaultFieldWidget.cs New default widget for rendering non-specialized custom-field types.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/DefaultFieldWidget/DefaultFieldViewModel.cs View model for the default field widget.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/DefaultFieldWidget/Default.cshtml Renders a generic input and supports placeholder/min/max/etc.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Views/Shared/Components/CurrencyWidget/Default.cshtml Adds placeholder support for currency input.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Pages/WorksheetConfiguration/UpsertSectionModal.cshtml.cs Adds FieldWidth binding/validation and persists width into section definition.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Pages/WorksheetConfiguration/UpsertSectionModal.cshtml Adds slider/number controls to configure per-section field width.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Pages/WorksheetConfiguration/UpsertCustomFieldModal.js New modal script for tabbed UI, hints, and validation badge behavior.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Pages/WorksheetConfiguration/UpsertCustomFieldModal.cshtml.cs Adds custom-field display/security options and merges them into definitions.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Pages/WorksheetConfiguration/UpsertCustomFieldModal.cshtml Refactors modal into Display/Attributes tabs and adds new form controls.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Pages/WorksheetConfiguration/Index.js Adds column resizer and client-side filters (published/unpublished/archived).
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Pages/WorksheetConfiguration/Index.css Adds layout styles for resizer, filters, and custom-field modal tab UI.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Pages/WorksheetConfiguration/Index.cshtml Updates worksheet configuration layout (sticky header, filters, resizable columns).
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Shared/Worksheets/Definitions/CustomFieldDefinition.cs Extends field definition schema with UI behavior (hidden/disabled/label/placeholder/etc.).
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Shared/Localization/Flex/en.json Shortens several worksheet configuration button labels.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/Worksheets/WorksheetSectionAppService.cs Persists section field width into Definition JSON.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/Worksheets/WorksheetAppService.cs Adds Archive API to toggle worksheet archived state.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationAutoMapperProfile.cs Parses fieldWidth from section definition JSON into DTO.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/Domain/Worksheets/WorksheetSection.cs Adds Definition jsonb storage to worksheet sections.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/Domain/Worksheets/Worksheet.cs Adds IsArchived state + setter and extends section update to include definition.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Worksheets/WorksheetSectionDto.cs Adds FieldWidth and Definition to section DTO.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Worksheets/WorksheetDto.cs Adds IsArchived to worksheet DTO.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Worksheets/IWorksheetAppService.cs Exposes Archive API contract.
applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Worksheets/EditSectionDto.cs Adds FieldWidth to section edit DTO.

Comment on lines +204 to +207
function makeSectionsAndFieldsSortable() {
makeCustomFieldsSortable();
makeSectionsSortable();
}
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

This file now defines makeSectionsAndFieldsSortable/makeCustomFieldsSortable/makeSectionsSortable (and related helpers) twice: once inside the $(function(){...}) closure and again as global functions below. Because the closure-scoped versions are the ones being called (they shadow the globals), the new archived-aware disabled: isArchived logic added in the global versions won’t take effect, and archived worksheets will still be sortable. Remove the duplicate set, or update the existing closure-scoped implementations to include the archived check and keep only one source of truth.

Copilot uses AI. Check for mistakes.
Comment on lines +213 to +216
_ = new Sortable(div, {
animation: 150,
disabled: isArchived,
onEnd: function (evt) {
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

_ = new Sortable(...) assigns to an undeclared identifier, creating an implicit global (or throwing in strict mode) and potentially clobbering other globals (commonly _). Use const sortable = new Sortable(...) (or just new Sortable(...) if you don’t need the instance) to avoid leaking globals.

Copilot uses AI. Check for mistakes.
Comment on lines +49 to +56
var fieldStyleAttr = !string.IsNullOrEmpty(fieldDef?.Style) ? $" style=\"{fieldDef.Style}\"" : "";
var fieldExtraCssClass = !string.IsNullOrEmpty(fieldDef?.CssClass) ? $" {fieldDef.CssClass}" : "";
var labelStyleAttr = !string.IsNullOrEmpty(fieldDef?.LabelStyle) ? $" style=\"{fieldDef.LabelStyle}\"" : "";

<div class="worksheet_field worksheet_field_@Model.UiAnchor @labelPositionClass@fieldExtraCssClass"
@Html.Raw(fieldDef?.IsHidden == true ? "hidden" : "")
@Html.Raw(fieldWidthStyle)
@Html.Raw(fieldStyleAttr)>
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

fieldDef.Style is injected into the DOM via @Html.Raw(fieldStyleAttr) where fieldStyleAttr is built from persisted JSON. This bypasses Razor’s output encoding and allows attribute-breaking payloads (e.g., quotes) which can become XSS. Prefer binding as an encoded attribute value (e.g., style="@fieldDef.Style") and/or validate/sanitize allowed CSS before persisting; avoid Html.Raw for user-controlled strings. The same concern applies to labelStyleAttr on the <label>.

Copilot uses AI. Check for mistakes.
Comment on lines +114 to +122
var existingDef = JsonSerializer.Deserialize<CustomFieldDefinition>(customField.Definition);
IsHidden = existingDef?.IsHidden ?? false;
HideLabel = existingDef?.HideLabel ?? false;
IsDisabled = existingDef?.IsDisabled ?? false;
LabelPosition = existingDef?.LabelPosition ?? "Top";
LabelStyle = existingDef?.LabelStyle;
LabelCssClass = existingDef?.LabelCssClass;
SecurityClassification = existingDef?.SecurityClassification;
Placeholder = existingDef?.Placeholder;
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

JsonSerializer.Deserialize<CustomFieldDefinition>(customField.Definition) can throw if the stored JSON is malformed, which would fail the modal GET with a 500. Consider wrapping this in a JsonException catch (and defaulting the new UI fields), or reuse the existing ConvertDefinition(...) helper which already handles JsonException by returning null.

Suggested change
var existingDef = JsonSerializer.Deserialize<CustomFieldDefinition>(customField.Definition);
IsHidden = existingDef?.IsHidden ?? false;
HideLabel = existingDef?.HideLabel ?? false;
IsDisabled = existingDef?.IsDisabled ?? false;
LabelPosition = existingDef?.LabelPosition ?? "Top";
LabelStyle = existingDef?.LabelStyle;
LabelCssClass = existingDef?.LabelCssClass;
SecurityClassification = existingDef?.SecurityClassification;
Placeholder = existingDef?.Placeholder;
try
{
var existingDef = JsonSerializer.Deserialize<CustomFieldDefinition>(customField.Definition);
IsHidden = existingDef?.IsHidden ?? false;
HideLabel = existingDef?.HideLabel ?? false;
IsDisabled = existingDef?.IsDisabled ?? false;
LabelPosition = existingDef?.LabelPosition ?? "Top";
LabelStyle = existingDef?.LabelStyle;
LabelCssClass = existingDef?.LabelCssClass;
SecurityClassification = existingDef?.SecurityClassification;
Placeholder = existingDef?.Placeholder;
}
catch (JsonException)
{
// Preserve the existing/default UI field values when stored JSON is malformed.
}

Copilot uses AI. Check for mistakes.
Comment on lines +22 to 24
<button data-worksheet-id="@worksheet.Id" data-is-archived="true" class="btn btn-light archive-worksheet-btn worksheet-btn" type="button">
<i class="fl fl-open-folder"></i> <span>Unarchive</span>
</button>
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

The button text "Unarchive" is hard-coded instead of localized like the other worksheet action buttons in this view. Please add a localization key (e.g., Worksheet:Configuration:UnarchiveWorksheetButtonText) and use @L[...] here for consistency and to support non-English locales.

Copilot uses AI. Check for mistakes.
Comment on lines +49 to +51
<button data-worksheet-id="@worksheet.Id" data-is-archived="false" class="btn btn-light archive-worksheet-btn worksheet-btn" type="button">
<i class="fl fl-folder"></i> <span>Archive</span>
</button>
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

The button text "Archive" is hard-coded instead of localized like the other worksheet action buttons in this view. Please add a localization key (e.g., Worksheet:Configuration:ArchiveWorksheetButtonText) and use @L[...] here for consistency and to support non-English locales.

Copilot uses AI. Check for mistakes.
if (doc.RootElement.TryGetProperty("fieldWidth", out var prop) && prop.TryGetInt32(out var value))
return value > 0 ? value : null;
}
catch { /* malformed JSON — fall through */ }
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

ParseFieldWidth uses a blanket catch {} which will swallow non-JSON failures (e.g., OOM, cancellation) and makes troubleshooting harder. Consider narrowing this to catch (JsonException) (and optionally FormatException) so unexpected failures still surface while still treating malformed JSON as “no fieldWidth”.

Suggested change
catch { /* malformed JSON — fall through */ }
catch (JsonException) { /* malformed JSON — fall through */ }

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <copilot@github.com>
@github-actions
Copy link
Copy Markdown

🧪 Unit Test Results (Parallel Execution)

Tests

📊 Summary

Result Count
✅ Passed 621
❌ Failed 0
⚠️ Skipped 0

📄 HTML Reports

  • Merged Tests (HTML): Included in artifacts
    Generated automatically by CI.

@JamesPasta JamesPasta merged commit ba8691a into dev Apr 27, 2026
21 of 22 checks passed
@github-actions
Copy link
Copy Markdown

🧪 Unit Test Results (Parallel Execution)

Tests

📊 Summary

Result Count
✅ Passed 621
❌ Failed 0
⚠️ Skipped 0

📄 HTML Reports

  • Merged Tests (HTML): Included in artifacts
    Generated automatically by CI.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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