Skip to content

feat: support list values in resource field component#202

Open
gkrajniak wants to merge 6 commits into
mainfrom
feat/support-list-values
Open

feat: support list values in resource field component#202
gkrajniak wants to merge 6 commits into
mainfrom
feat/support-list-values

Conversation

@gkrajniak

@gkrajniak gkrajniak commented Jul 10, 2026

Copy link
Copy Markdown
Member

Add collection display to the resource filed component

Screenshot 2026-07-10 at 14 27 29

Summary by CodeRabbit

  • New Features

    • Added expandable card-based rendering for collection fields.
    • Collection cards show concise previews and expand to display detailed sub-fields.
    • Added support for rich collection cells in table card views, including tags, links, secrets, status styling, and actions.
    • Added accessible expand/collapse controls and responsive collection styling.
  • Bug Fixes

    • Collection fields now render only when valid array data is available.
  • Tests

    • Added coverage for previews, expansion behavior, empty entries, invalid data, and rich collection rendering.

Signed-off-by: gkrajniak <gkrajniak@gmail.com>
Signed-off-by: gkrajniak <gkrajniak@gmail.com>
…he collection to propertyCollection

Signed-off-by: gkrajniak <gkrajniak@gmail.com>
…he collection to propertyCollection

Signed-off-by: gkrajniak <gkrajniak@gmail.com>
Signed-off-by: gkrajniak <gkrajniak@gmail.com>
Signed-off-by: gkrajniak <gkrajniak@gmail.com>
@gkrajniak gkrajniak self-assigned this Jul 10, 2026
@gkrajniak gkrajniak added the enhancement New feature or request label Jul 10, 2026
@gkrajniak gkrajniak requested review from a team as code owners July 10, 2026 12:28
@gkrajniak gkrajniak moved this to In review in OpenMFP Development Jul 10, 2026
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an expandable card-based renderer for propertyCollection fields, integrates it into ResourceField, adds styling and tests, and introduces a rich collection-cell Storybook story.

Changes

Resource collection rendering

Layer / File(s) Summary
Collection card component
projects/ngx/declarative-ui/resource-field/resource-collection-field/*
Extracts array entries, derives sub-field rows and previews, renders expandable cards, and validates rendering and toggle behavior with tests.
ResourceField collection integration
projects/ngx/declarative-ui/resource-field/resource-field.component.*
Detects collection definitions, delegates rendering to mfp-resource-collection-field, preserves scalar rendering, and adds collection layout styling and tests.
Rich collection Storybook example
projects/ngx/declarative-ui/stories/declarative-table-card.stories.ts
Adds rich collection data, sub-field configurations, icons, and the exported WithRichCells story.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WithRichCells
  participant ResourceField
  participant ResourceCollectionField
  participant RowResourceField
  WithRichCells->>ResourceField: provide collection field definition and resource
  ResourceField->>ResourceCollectionField: render propertyCollection
  ResourceCollectionField->>ResourceCollectionField: derive entries and preview
  ResourceCollectionField->>RowResourceField: render expanded sub-fields
Loading

Suggested reviewers: lpgarzonr, Sobyt483

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding list/collection value support to the resource field component.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/support-list-values

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gkrajniak gkrajniak requested a review from Sobyt483 July 10, 2026 12:31
@gkrajniak gkrajniak changed the title Feat/support list values feat: support list values in resource field component Jul 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
projects/ngx/declarative-ui/resource-field/resource-collection-field/resource-collection-field.component.html (1)

2-2: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider tracking entries by a stable key instead of $index.

Using track $index means Angular reuses DOM nodes by position, not identity. If the underlying array is reordered or items are inserted/deleted in the middle, expanded-state and DOM will be incorrectly associated with the wrong entry. If entries have a natural unique field (e.g. id, name), track by that instead.

♻️ Suggested track expression
-  `@for` (entry of entries(); track $index; let index = $index) {
+  `@for` (entry of entries(); track entry.id ?? $index; let index = $index) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@projects/ngx/declarative-ui/resource-field/resource-collection-field/resource-collection-field.component.html`
at line 2, Replace track $index in the `@for` loop of
ResourceCollectionFieldComponent with a stable unique property from each entry,
such as entry.id or entry.name, so DOM and expanded state remain associated with
the correct item after reordering or middle insertion/deletion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@projects/ngx/declarative-ui/resource-field/resource-collection-field/resource-collection-field.component.ts`:
- Around line 56-61: Update the entries computed in the resource collection
field component to pass the field definition’s jsonPathExpression along with
collectionPath() to getResourceValueByJsonPath, preserving the fallback to
property so both path configurations resolve correctly.

In `@projects/ngx/declarative-ui/resource-field/resource-field.component.ts`:
- Around line 33-54: Reorder the `@Component` decorator keys in
ResourceFieldComponent to satisfy sort-keys-in-type-decorator: move host after
encapsulation, while preserving the existing imports, template, changeDetection,
and schemas configuration.

---

Nitpick comments:
In
`@projects/ngx/declarative-ui/resource-field/resource-collection-field/resource-collection-field.component.html`:
- Line 2: Replace track $index in the `@for` loop of
ResourceCollectionFieldComponent with a stable unique property from each entry,
such as entry.id or entry.name, so DOM and expanded state remain associated with
the correct item after reordering or middle insertion/deletion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bee59355-7836-4279-a0a4-c167c3d1dc4d

📥 Commits

Reviewing files that changed from the base of the PR and between 5c9ba3a and db0e8dd.

📒 Files selected for processing (9)
  • projects/ngx/declarative-ui/resource-field/resource-collection-field/resource-collection-field.component.html
  • projects/ngx/declarative-ui/resource-field/resource-collection-field/resource-collection-field.component.scss
  • projects/ngx/declarative-ui/resource-field/resource-collection-field/resource-collection-field.component.spec.ts
  • projects/ngx/declarative-ui/resource-field/resource-collection-field/resource-collection-field.component.ts
  • projects/ngx/declarative-ui/resource-field/resource-field.component.html
  • projects/ngx/declarative-ui/resource-field/resource-field.component.scss
  • projects/ngx/declarative-ui/resource-field/resource-field.component.spec.ts
  • projects/ngx/declarative-ui/resource-field/resource-field.component.ts
  • projects/ngx/declarative-ui/stories/declarative-table-card.stories.ts

Comment on lines +56 to +61
protected readonly entries = computed<Record<string, unknown>[]>(() => {
const value = getResourceValueByJsonPath(this.resource() ?? {}, {
property: this.collectionPath(),
});
return Array.isArray(value) ? (value as Record<string, unknown>[]) : [];
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

entries computed ignores jsonPathExpression from the field definition.

getResourceValueByJsonPath checks field.jsonPathExpression || field.property, but only property is passed here. If a collection field uses jsonPathExpression instead of (or alongside) property, the array will silently resolve to [] with no error logged.

🔧 Proposed fix
 protected readonly entries = computed<Record<string, unknown>[]>(() => {
-    const value = getResourceValueByJsonPath(this.resource() ?? {}, {
-      property: this.collectionPath(),
-    });
+    const fd = this.fieldDefinition();
+    const value = getResourceValueByJsonPath(this.resource() ?? {}, {
+      jsonPathExpression: fd.jsonPathExpression,
+      property: this.collectionPath(),
+    });
     return Array.isArray(value) ? (value as Record<string, unknown>[]) : [];
   });
📝 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.

Suggested change
protected readonly entries = computed<Record<string, unknown>[]>(() => {
const value = getResourceValueByJsonPath(this.resource() ?? {}, {
property: this.collectionPath(),
});
return Array.isArray(value) ? (value as Record<string, unknown>[]) : [];
});
protected readonly entries = computed<Record<string, unknown>[]>(() => {
const fd = this.fieldDefinition();
const value = getResourceValueByJsonPath(this.resource() ?? {}, {
jsonPathExpression: fd.jsonPathExpression,
property: this.collectionPath(),
});
return Array.isArray(value) ? (value as Record<string, unknown>[]) : [];
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@projects/ngx/declarative-ui/resource-field/resource-collection-field/resource-collection-field.component.ts`
around lines 56 - 61, Update the entries computed in the resource collection
field component to pass the field definition’s jsonPathExpression along with
collectionPath() to getResourceValueByJsonPath, preserving the fallback to
property so both path configurations resolve correctly.

Comment on lines +33 to 54
imports: [
Icon,
BooleanValue,
LinkValue,
SecretValue,
Button,
TagListValue,
// `ResourceCollectionField` imports this component back (each expanded
// card renders its sub-fields via `mfp-resource-field`), so the two form
// a module-init cycle. `forwardRef` defers resolution until the template
// is instantiated, by which point both classes are defined.
forwardRef(() => ResourceCollectionField),
],
templateUrl: './resource-field.component.html',
styleUrl: './resource-field.component.scss',
host: {
'[class.resource-field--collection]': 'isCollection()',
},
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.ShadowDom,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix @Component decorator key ordering to satisfy ESLint.

Static analysis reports an @angular-eslint/sort-keys-in-type-decorator error: host should appear after encapsulation, not before changeDetection. This is a lint error that may fail CI.

🔧 Proposed fix
 `@Component`({
   selector: 'mfp-resource-field',
   imports: [
     Icon,
     BooleanValue,
     LinkValue,
     SecretValue,
     Button,
     TagListValue,
     forwardRef(() => ResourceCollectionField),
   ],
   templateUrl: './resource-field.component.html',
   styleUrl: './resource-field.component.scss',
-  host: {
-    '[class.resource-field--collection]': 'isCollection()',
-  },
   changeDetection: ChangeDetectionStrategy.OnPush,
   encapsulation: ViewEncapsulation.ShadowDom,
+  host: {
+    '[class.resource-field--collection]': 'isCollection()',
+  },
   schemas: [CUSTOM_ELEMENTS_SCHEMA],
 })
📝 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.

Suggested change
imports: [
Icon,
BooleanValue,
LinkValue,
SecretValue,
Button,
TagListValue,
// `ResourceCollectionField` imports this component back (each expanded
// card renders its sub-fields via `mfp-resource-field`), so the two form
// a module-init cycle. `forwardRef` defers resolution until the template
// is instantiated, by which point both classes are defined.
forwardRef(() => ResourceCollectionField),
],
templateUrl: './resource-field.component.html',
styleUrl: './resource-field.component.scss',
host: {
'[class.resource-field--collection]': 'isCollection()',
},
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.ShadowDom,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
imports: [
Icon,
BooleanValue,
LinkValue,
SecretValue,
Button,
TagListValue,
// `ResourceCollectionField` imports this component back (each expanded
// card renders its sub-fields via `mfp-resource-field`), so the two form
// a module-init cycle. `forwardRef` defers resolution until the template
// is instantiated, by which point both classes are defined.
forwardRef(() => ResourceCollectionField),
],
templateUrl: './resource-field.component.html',
styleUrl: './resource-field.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.ShadowDom,
host: {
'[class.resource-field--collection]': 'isCollection()',
},
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
🧰 Tools
🪛 ESLint

[error] 48-50: Keys in @Component decorator should be ordered: selector, imports, templateUrl, styleUrl, changeDetection, encapsulation, host, schemas

(@angular-eslint/sort-keys-in-type-decorator)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@projects/ngx/declarative-ui/resource-field/resource-field.component.ts`
around lines 33 - 54, Reorder the `@Component` decorator keys in
ResourceFieldComponent to satisfy sort-keys-in-type-decorator: move host after
encapsulation, while preserving the existing imports, template, changeDetection,
and schemas configuration.

Source: Linters/SAST tools

@gkrajniak

Copy link
Copy Markdown
Member Author

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

Labels

enhancement New feature or request

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

1 participant