Skip to content

Conversation

@abhinandan13jan
Copy link
Contributor

@abhinandan13jan abhinandan13jan commented Jul 3, 2025

Issue

https://issues.redhat.com/browse/SECURESIGN-2587

Screenshot

Screenshot 2025-07-04 at 6 01 21 PM Screenshot 2025-07-04 at 6 01 39 PM

Summary by Sourcery

Refactor trust roots pages by extracting list rows and drawer tabs into reusable components, centralizing sample data in a new model, and enhance the metadata table with a “Role” column.

New Features:

  • Add a card for Metadata of TrustRoot featuring available TUF data
  • Introduce a centralized exampleTrustRoots data model with expanded schema including roles.
  • Implement dedicated tab components (Metadata, Certificates, Info) with a fallback for missing trust roots.
  • Add TrustRootRow and StatusIcon components for list rendering with dynamic status indicators.

Enhancements:

  • Replace hard-coded row generation with dynamic mapping over rowData.
  • Refactor TrustRootsDataList and TrustRootsDrawerContent to delegate rendering to subcomponents.
  • Move example data and types into src/app/Trust/TrustRoots/data/TrustRoots.data.tsx for clarity.

Chores:

  • Remove deprecated inline icon and dropdown code and outdated TrustRoots.data.tsx file.

@sourcery-ai
Copy link

sourcery-ai bot commented Jul 3, 2025

Reviewer's Guide

This PR restructures the Trust Roots pages by extracting row and drawer subcomponents, centralizing the data model in a new file, and enhancing the metadata view with a new "role" column.

Entity relationship diagram for TrustRootKind and related data types

erDiagram
  TRUSTROOTKIND ||--o{ CERTIFICATE : has
  TRUSTROOTKIND ||--o{ TUF_METADATA : has
  TRUSTROOTKIND ||--o{ TRUSTROOTEVENTS : has
  CERTIFICATE {
    string subject
    string issuer
    string type
    string status
    string fingerprint
  }
  TUF_METADATA {
    string role
    int version
    string expires
    string status
  }
  TRUSTROOTEVENTS {
    string timestamp
    string type
    string message
  }
  TRUSTROOTKIND {
    string id
    string name
    string source
    string type
    string lastUpdated
  }
Loading

Class diagram for the new Trust Roots data model and components

classDiagram
  class TrustRootKind {
    +string id
    +string name
    +string source
    +string type
    +string lastUpdated
    +Certificate[] certificates
    +TUFMetadata[] tufMetadata
    +TrustRootEvents[] events
  }
  class Certificate {
    +string subject
    +string issuer
    +string type
    +string status
    +string fingerprint
  }
  class TUFMetadata {
    +string role
    +number version
    +string expires
    +STATUS status
  }
  class TrustRootRow {
    +string id
    +LastStatus lastStatus
    +boolean isRunning
    +TrustRootKind trustRoot
  }
  class TrustRootsDrawerContent {
    +string trustRootId
  }
  class TrustRootMetadataTab {
    +TrustRootKind trustRoot
  }
  class TrustRootCertificateTab {
    +TrustRootKind trustRoot
  }
  class TrustRootInfoTab {
    +TrustRootKind trustRoot
  }
  TrustRootKind "1" -- "*" Certificate : contains
  TrustRootKind "1" -- "*" TUFMetadata : contains
  TrustRootKind "1" -- "*" TrustRootEvents : contains
  TrustRootRow "1" -- "1" TrustRootKind : references
  TrustRootsDrawerContent "1" -- "1" TrustRootKind : finds
  TrustRootMetadataTab "1" -- "1" TrustRootKind : displays
  TrustRootCertificateTab "1" -- "1" TrustRootKind : displays
  TrustRootInfoTab "1" -- "1" TrustRootKind : displays
Loading

File-Level Changes

Change Details Files
Modularize row rendering
  • Removed inline getRow and action logic
  • Added getStatus and getIsRunning helpers returning dummy states
  • Replaced manual rows with rowData.map rendering TrustRootRow
src/app/Trust/TrustRoots/components/TrustRootsDataList.tsx
src/app/Trust/TrustRoots/components/TrustRootRow.tsx
src/app/Trust/TrustRoots/components/StatusIcon.tsx
Refactor drawer content into tab components
  • Removed embedded tables and pagination from TrustRootsDrawerContent
  • Introduced TrustRootMetadataTab, TrustRootCertificateTab, TrustRootInfoTab, TrustRootNotFound components
  • Updated TrustRootsDrawerContent to accept trustRootId and delegate to subcomponents
src/app/Trust/TrustRoots/components/TrustRootsDrawerContent.tsx
src/app/Trust/TrustRoots/components/DraweContents/TrustRootMetadataTab.tsx
src/app/Trust/TrustRoots/components/DraweContents/TrustRootCertificateTab.tsx
src/app/Trust/TrustRoots/components/DraweContents/TrustRootInfoTab.tsx
src/app/Trust/TrustRoots/components/TrustRootNotFound.tsx
Centralize data model and examples
  • Created new TrustRoots.data.tsx with domain interfaces and exampleTrustRoots array
  • Removed old TrustRoots.data.tsx and unused imports
  • Defined STATUS enum and TrustRootKind types
src/app/Trust/TrustRoots/data/TrustRoots.data.tsx
Add "role" column to metadata table
  • Extended TUFMetadata interface with optional role
  • Added Role header and cell in TrustRootMetadataTab table
src/app/Trust/TrustRoots/data/TrustRoots.data.tsx
src/app/Trust/TrustRoots/components/DraweContents/TrustRootMetadataTab.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @abhinandan13jan - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `src/app/Trust/TrustRoots/components/DraweContents/TrustRootCertificateTab.tsx:28` </location>
<code_context>
+          </Tr>
+        </Thead>
+        <Tbody>
+          {trustRoot.certificates.map((cert, idx) => (
+            <Tr key={idx}>
+              <Td>{cert.subject}</Td>
</code_context>

<issue_to_address>
No unique key for certificates.

Use a unique identifier from each certificate, such as a fingerprint, as the key instead of the array index to ensure stable React reconciliation.

Suggested implementation:

```typescript
          {trustRoot.certificates.map((cert) => (
            <Tr key={cert.fingerprint}>

```

This change assumes that each certificate object in `trustRoot.certificates` has a unique `fingerprint` property. If the property is named differently or not guaranteed to be unique, you should use another unique identifier available on the certificate object.
</issue_to_address>

### Comment 2
<location> `src/app/Trust/TrustRoots/components/DraweContents/TrustRootMetadataTab.tsx:28` </location>
<code_context>
+          </Tr>
+        </Thead>
+        <Tbody>
+          {trustRoot.tufMetadata.map((metadata, idx) => (
+            <Tr key={idx}>
+              <Td>{metadata.version}</Td>
</code_context>

<issue_to_address>
Array index used as key for metadata rows.

Prefer using a unique property from the metadata object, like version or a combination of role and version, as the key instead of the array index.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
          {trustRoot.tufMetadata.map((metadata, idx) => (
            <Tr key={idx}>
=======
          {trustRoot.tufMetadata.map((metadata) => (
            <Tr key={`${metadata.role}-${metadata.version}`}>
>>>>>>> REPLACE

</suggested_fix>

### Comment 3
<location> `src/app/Trust/TrustRoots/components/StatusIcon.tsx:8` </location>
<code_context>
+import { MinusIcon } from '@patternfly/react-icons';
+
+type StatusIconProps = {
+  status: string;
+};
+
</code_context>

<issue_to_address>
StatusIcon prop type could be more specific.

Consider changing the status prop type to 'success' | 'error' | null for improved type safety and clarity.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
type StatusIconProps = {
  status: string;
};
=======
type StatusIconProps = {
  status: 'success' | 'error' | null;
};
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

</Tr>
</Thead>
<Tbody>
{trustRoot.certificates.map((cert, idx) => (
Copy link

Choose a reason for hiding this comment

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

suggestion: No unique key for certificates.

Use a unique identifier from each certificate, such as a fingerprint, as the key instead of the array index to ensure stable React reconciliation.

Suggested implementation:

          {trustRoot.certificates.map((cert) => (
            <Tr key={cert.fingerprint}>

This change assumes that each certificate object in trustRoot.certificates has a unique fingerprint property. If the property is named differently or not guaranteed to be unique, you should use another unique identifier available on the certificate object.

Comment on lines 28 to 29
{trustRoot.tufMetadata.map((metadata, idx) => (
<Tr key={idx}>
Copy link

Choose a reason for hiding this comment

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

suggestion (bug_risk): Array index used as key for metadata rows.

Prefer using a unique property from the metadata object, like version or a combination of role and version, as the key instead of the array index.

Suggested change
{trustRoot.tufMetadata.map((metadata, idx) => (
<Tr key={idx}>
{trustRoot.tufMetadata.map((metadata) => (
<Tr key={`${metadata.role}-${metadata.version}`}>

@abhinandan13jan abhinandan13jan force-pushed the add-trust-colum branch 3 times, most recently from 2ae0068 to 1bd38ba Compare July 4, 2025 12:32
@abhinandan13jan abhinandan13jan changed the title chore(trust-pages): refactor trust pages and add role column chore(trust-pages): refactor trust pages and add metadata card Jul 4, 2025
@abhinandan13jan abhinandan13jan changed the title chore(trust-pages): refactor trust pages and add metadata card feat(trust-pages): refactor trust pages and add role column Jul 4, 2025
@abhinandan13jan abhinandan13jan changed the title feat(trust-pages): refactor trust pages and add role column feat(trust-pages): refactor trust pages and add metadata card Jul 4, 2025
Copy link
Collaborator

@kahboom kahboom left a comment

Choose a reason for hiding this comment

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

Hey @abhinandan13jan , overall the PR looks great. Thanks for the screenshot, referencing the Jira from the PR, and linking to this from the Jira. I left a feedback point about accessing the tufMetadata array with square bracket notation, and about removing the commented code, but I wouldn't call these blocking. Thanks for this contribution!! Hope you have a nice weekend.

}

const TrustRootMetadataTab: React.FC<TrustRootMetadataTabProps> = ({ trustRoot }) => {
if (!trustRoot) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here we should also check if tufMetadata exists and its length is greater than 0, see below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes makes sense. I updated the early exit check

if (!trustRoot) {
return <TrustRootNotFound />;
}
const latestTUF = trustRoot?.tufMetadata[0];
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's worth double checking that the backend will not return a trustRoot object at all if the tufMetadata array is empty. Because if it still does, and that array is empty, this will result in a type error when we try to access its properties. One way around this is to check the length of tufMetadata is greater than 0 (see above).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated in earlier line


export default TrustRootMetadataTab;

// const table = <>
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we can remove this now and add in a table in the future if customers request it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

@abhinandan13jan abhinandan13jan merged commit 84aa096 into securesign:main Jul 7, 2025
1 check passed
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