Skip to content

feat: export Roles page as a component and consume it in apps/admin#1349

Open
paanSinghCoder wants to merge 12 commits intomainfrom
refactor/admin-ui-child
Open

feat: export Roles page as a component and consume it in apps/admin#1349
paanSinghCoder wants to merge 12 commits intomainfrom
refactor/admin-ui-child

Conversation

@paanSinghCoder
Copy link
Contributor

@paanSinghCoder paanSinghCoder commented Jan 29, 2026

  • Move roles page to @raystack/frontier/admin
  • Moved roles UI from apps/admin/src/containers/roles.list/ into web/lib/admin/views/roles/ as a router-agnostic page.
  • Exported RolesPage from @raystack/frontier/admin with optional props: selectedRoleId, onSelectRole, onCloseDetail, appName.
  • Added lib/admin shared pieces: utils (helper, connect-timestamp), components (PageTitle, SheetHeader, PageHeader) and CSS modules.
  • Wired admin app via RolesPageWithRouter (uses useParams/useNavigate) and routes roles + roles/:roleId.
  • Removed containers/roles.list from the app; roles are now implemented in the lib.

Note: To test this in local, change frontier version to "@raystack/frontier": "workspace:^", in frontier/web/apps/admin/package.json

Technical Details

Test Plan

  • Manual testing completed
  • Build and type checking passes

Summary by CodeRabbit

  • New Features

    • Added new admin page components (headers, sheets) with breadcrumb navigation support.
    • Introduced improved roles management interface with better selection and detail view handling.
  • Refactor

    • Simplified roles routing and navigation workflow.
    • Enhanced role column display to show items vertically instead of comma-separated.
    • Improved state management for role selection across the admin interface.
  • Chores

    • Published admin distribution as a public module export.
    • Updated dependencies and build configuration.

@vercel
Copy link

vercel bot commented Jan 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Feb 3, 2026 11:33am

@paanSinghCoder paanSinghCoder changed the title Refactor/admin UI child feat: export Roles page as a component and consume it in apps/admin Jan 29, 2026
@coveralls
Copy link

coveralls commented Jan 29, 2026

Pull Request Test Coverage Report for Build 21628546856

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 37.983%

Totals Coverage Status
Change from base Build 21623958951: 0.0%
Covered Lines: 15956
Relevant Lines: 42008

💛 - Coveralls

Base automatically changed from refactor/admin-ui to main January 29, 2026 08:38
@paanSinghCoder paanSinghCoder changed the base branch from main to refactor/admin-ui January 29, 2026 08:39
@paanSinghCoder paanSinghCoder changed the base branch from refactor/admin-ui to main January 29, 2026 08:39
@paanSinghCoder paanSinghCoder changed the base branch from main to refactor/admin-ui January 29, 2026 08:40
@paanSinghCoder paanSinghCoder changed the base branch from refactor/admin-ui to main January 29, 2026 08:41
@paanSinghCoder paanSinghCoder changed the base branch from main to refactor/admin-ui January 29, 2026 08:41
@paanSinghCoder paanSinghCoder force-pushed the refactor/admin-ui-child branch from e887b1e to ec4b710 Compare January 29, 2026 08:56
@paanSinghCoder paanSinghCoder changed the base branch from refactor/admin-ui to main January 29, 2026 08:57
Copy link
Member

Choose a reason for hiding this comment

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

Just name it RolesPage

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

<Route path=":roleId" element={<RoleDetails />} />
</Route>
<Route path="roles" element={<RolesPageWithRouter />} />
<Route path="roles/:roleId" element={<RolesPageWithRouter />} />
Copy link
Member

Choose a reason for hiding this comment

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

we can use nested routes here


.breadcrumb a {
text-decoration: none;
color: #007bff;
Copy link
Member

Choose a reason for hiding this comment

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

can we use css variables here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Out of scope for this PR. Will be picked up in another ticket.

padding: 0;
margin: 0;
display: flex;
font-size: 16px;
Copy link
Member

Choose a reason for hiding this comment

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

can we use css variables here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Out of scope for this PR. Will be picked up in another ticket.


.breadcrumb a::before {
content: ">";
color: #666;
Copy link
Member

Choose a reason for hiding this comment

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

same as 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.

Out of scope for this PR. Will be picked up in another ticket.


.breadcrumbItem::before {
content: ">";
color: #666;
Copy link
Member

Choose a reason for hiding this comment

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

same as 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.

Out of scope for this PR. Will be picked up in another ticket.

align="center"
justify="between"
className={className}
style={{ padding: "16px 24px", ...style }}
Copy link
Member

Choose a reason for hiding this comment

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

can we move add class for this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Out of scope for this PR. Will be picked up in another ticket.

>
<Flex align="center" gap="medium">
<Flex align="center" gap="small" className={styles.breadcrumb}>
<Text style={{ fontSize: "14px", fontWeight: "500" }}>{title}</Text>
Copy link
Member

Choose a reason for hiding this comment

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

fontWeight and fontSize can be props

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Out of scope for this PR. Will be picked up in another ticket.

export function SheetHeader({ title, onClick, "data-testid": dataTestId }: SheetHeaderProps) {
return (
<Flex justify="between" style={styles.header}>
<Text size={4} style={{ fontWeight: "500" }}>
Copy link
Member

Choose a reason for hiding this comment

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

fontWeight can be props

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Out of scope for this PR. Will be picked up in another ticket.

@rsbh
Copy link
Member

rsbh commented Feb 4, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

This PR refactors the roles management UI to use controlled component patterns instead of router-driven hooks, introduces new reusable header components (PageHeader, PageTitle, SheetHeader), updates dependency resolution to workspace reference, and exposes the admin library as a public export.

Changes

Cohort / File(s) Summary
Admin App Configuration
web/apps/admin/.eslintrc.cjs, web/apps/admin/package.json
Removed redundant ESLint config file; updated @raystack/frontier dependency to workspace reference for local development resolution.
Admin App Routing & Pages
web/apps/admin/src/routes.tsx, web/apps/admin/src/pages/roles/RolesPage.tsx
Restructured routing to use new RolesPage component; now single component handles both /roles and /roles/:roleId paths via URL params instead of nested routes.
Admin App Utilities
web/apps/admin/src/utils/helper.ts
Fixed TypeScript type issue in CSV blob construction by casting chunks to BlobPart[].
Admin Library Header Components
web/lib/admin/components/PageHeader.tsx, web/lib/admin/components/PageTitle.tsx, web/lib/admin/components/SheetHeader.tsx, web/lib/admin/components/page-header.module.css
Added three new reusable header components: PageHeader (title + breadcrumbs), PageTitle (document title management), and SheetHeader (modal header with close). Includes breadcrumb styling via CSS module.
Admin Library Utilities
web/lib/admin/utils/connect-timestamp.ts, web/lib/admin/utils/helper.ts
Added timestampToDate() utility for protobuf timestamp conversion and reduceByKey() for array-to-map transformations.
Admin Library Roles View
web/lib/admin/views/roles/index.tsx, web/lib/admin/views/roles/details.tsx, web/lib/admin/views/roles/header.tsx, web/lib/admin/views/roles/columns.tsx, web/lib/admin/views/roles/roles.module.css
Refactored RolesView (formerly RoleList) to support controlled selectedRoleId prop and callbacks instead of router hooks; RoleDetails now receives role prop; switched to new PageHeader component; updated permissions column to display vertically; minor CSS formatting.
Admin Library Exports & Build Configuration
web/lib/admin/index.ts, web/lib/package.json, web/lib/tsup.config.ts
Added "use client" directive; exported RolesView as default; exposed ./admin export path in package.json with dist artifacts; added tsup build config for admin module.
ESLint Configuration
web/tools/eslint-config/index.js
Extracted extends array into named constant; removed 'turbo' from extends list.

Sequence Diagram

sequenceDiagram
    participant User
    participant RolesPage
    participant RolesView
    participant RoleDetails
    
    User->>RolesPage: Navigate to /roles or /roles/:id
    RolesPage->>RolesPage: Extract roleId from URL params
    RolesPage->>RolesView: Pass selectedRoleId & onSelectRole callback
    
    User->>RolesView: Click on role in list
    RolesView->>RolesView: handleRowClick(roleId)
    RolesView->>RolesPage: onSelectRole(roleId)
    RolesPage->>RolesPage: navigate(/roles/:id)
    
    RolesPage->>RolesView: Update selectedRoleId prop
    RolesView->>RolesView: Lookup role from data map
    RolesView->>RoleDetails: Pass resolved role object
    RoleDetails->>RoleDetails: Render role details
    
    User->>RolesView: Click close on detail sheet
    RolesView->>RolesPage: onCloseDetail()
    RolesPage->>RolesPage: navigate(/roles)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Hop hop, a refactor so neat,
Props now guide where routes would greet,
Headers bloom in components sublime,
Controlled state marches through time,
The roles dance differently, what a sweet feat!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: exporting a Roles page component and consuming it in the admin app.
Description check ✅ Passed The description covers all required sections from the template with substantial detail about the changes, technical decisions, and testing status.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/admin-ui-child

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@web/lib/admin/components/SheetHeader.tsx`:
- Around line 11-31: Replace the clickable Cross1Icon in SheetHeader with the
IconButton component from `@raystack/apsara` so the close control has proper
button semantics and an accessible name; update the import to include
IconButton, render IconButton (passing the Cross1Icon as its icon prop or
children), move the onClick handler from Cross1Icon to IconButton, add
aria-label (e.g., "Close sheet") and keep data-testid usage (use dataTestId or
default "admin-close-btn") to preserve tests.

In `@web/lib/admin/views/roles/index.tsx`:
- Around line 36-40: handleRowClick inconsistently maps Role.id to "" in the
onSelectRole branch but to undefined in the setInternalRoleId branch; make both
branches pass the same type (prefer leaving id as-is or using undefined
consistently). Update the handleRowClick callback to call onSelectRole(role.id)
(or onSelectRole(role.id ?? undefined) if callback expects string|undefined) and
setInternalRoleId(role.id) so both branches use role.id (string | undefined)
consistently; reference the handleRowClick function, the onSelectRole prop,
setInternalRoleId, and the Role.id field when making the change.

In `@web/tools/eslint-config/index.js`:
- Around line 2-7: The extendsList array currently omits 'turbo' while
package.json still lists eslint-config-turbo and client-demo/.eslintrc.js uses
the turbo/no-undeclared-env-vars rule; either re-add 'turbo' into the
extendsList (add 'turbo' to the extendsList constant so the turbo rules are
applied) or remove the eslint-config-turbo dependency from
web/tools/eslint-config/package.json and update client-demo/.eslintrc.js to stop
referencing turbo rules; locate and edit the extendsList constant and
package.json dependency to keep them consistent with the .eslintrc.js usage.
🧹 Nitpick comments (9)
web/tools/eslint-config/index.js (1)

2-7: Nitpick: Inconsistent quote style.

Line 5 uses double quotes ("eslint:recommended") while the other entries use single quotes. Consider using consistent quoting for readability.

🔧 Suggested fix
 const extendsList = [
   'next',
   'prettier',
-  "eslint:recommended",
+  'eslint:recommended',
   'plugin:test-selectors/recommended'
 ];
web/lib/admin/utils/helper.ts (1)

1-11: Avoid repeated object spreads in reduceByKey.
Current approach re-allocates the accumulator each iteration; mutating the accumulator reduces allocations on large arrays.

♻️ Proposed refactor
 export function reduceByKey<T extends Record<string, unknown>>(
   data: T[],
   key: keyof T
 ): Record<string, T> {
-  return data.reduce(
-    (acc, value) => ({
-      ...acc,
-      [String(value[key])]: value,
-    }),
-    {} as Record<string, T>
-  );
+  return data.reduce((acc, value) => {
+    acc[String(value[key])] = value;
+    return acc;
+  }, {} as Record<string, T>);
 }
web/lib/admin/views/roles/details.tsx (1)

4-12: Consider a null guard to avoid empty detail rendering.
If role is null, the component currently renders empty fields; an early return (or explicit empty state) keeps the UI cleaner and removes optional chaining.

♻️ Suggested guard
 export default function RoleDetails({ role }: { role: Role | null }) {
+  if (!role) return null;
   return (
     <Flex direction="column" gap={9}>
-      <Text size={4}>{role?.name}</Text>
+      <Text size={4}>{role.name}</Text>
       <Flex direction="column" gap={9}>
         <Grid columns={2} gap="small">
           <Text size={1}>Name</Text>
-          <Text size={1}>{role?.name}</Text>
+          <Text size={1}>{role.name}</Text>
         </Grid>
       </Flex>
     </Flex>
   );
 }
web/lib/admin/components/PageTitle.tsx (1)

8-16: Preserve the previous document title on unmount.
The cleanup currently resets to appName/empty, which can overwrite a prior title set elsewhere.

♻️ Suggested adjustment
-import { useEffect } from "react";
+import { useEffect, useRef } from "react";
@@
 export function PageTitle({ title, appName }: PageTitleProps) {
   const fullTitle = title && appName ? `${title} | ${appName}` : title ?? appName ?? "";
+  const prevTitleRef = useRef<string | null>(null);

   useEffect(() => {
+    if (prevTitleRef.current === null) {
+      prevTitleRef.current = document.title;
+    }
     if (fullTitle) document.title = fullTitle;
     return () => {
-      document.title = appName ?? "";
+      if (prevTitleRef.current !== null) {
+        document.title = prevTitleRef.current;
+      }
     };
-  }, [fullTitle, appName]);
+  }, [fullTitle]);
@@
   return null;
 }
web/lib/admin/views/roles/columns.tsx (1)

31-36: Prefer stable keys for permissions list items.
Line 33-34 uses the array index as the key; if permissions reorder, React can reuse DOM incorrectly. Consider keying by permission value (or a composite key if duplicates are possible).

♻️ Suggested tweak
-          {((info.getValue() as string[]) || []).map((p, i) => (
-            <span key={i}>{p}</span>
-          ))}
+          {((info.getValue() as string[]) || []).map(p => (
+            <span key={p}>{p}</span>
+          ))}
web/lib/admin/components/PageHeader.tsx (2)

5-10: Breadcrumb href property is defined but never used.

The PageHeaderTypes defines href?: string for breadcrumb items, but the component renders plain <span> elements (lines 32-34) instead of anchor tags. The CSS also has styles for .breadcrumb a that won't apply.

Either remove the href property from the type if links aren't needed, or render anchors when href is provided:

♻️ Proposed fix to support href
          {breadcrumb.map((item) => (
-            <span key={item.name} className={styles.breadcrumbItem}>
-              {item.name}
-            </span>
+            item.href ? (
+              <a key={item.name} href={item.href}>
+                {item.name}
+              </a>
+            ) : (
+              <span key={item.name} className={styles.breadcrumbItem}>
+                {item.name}
+              </span>
+            )
          ))}

31-35: Consider a more robust key for breadcrumb items.

Using item.name as the key could cause issues if breadcrumb items have duplicate names. Consider using the index as a fallback:

♻️ Proposed fix
-          {breadcrumb.map((item) => (
-            <span key={item.name} className={styles.breadcrumbItem}>
+          {breadcrumb.map((item, index) => (
+            <span key={`${item.name}-${index}`} className={styles.breadcrumbItem}>
web/lib/admin/components/page-header.module.css (2)

9-27: Anchor styles are currently unused.

The .breadcrumb a selectors (lines 9-27) define styles for anchor tags, but the PageHeader component currently renders <span> elements with the .breadcrumbItem class. These styles won't apply until the component is updated to render anchors when href is provided.


11-11: Consider using design tokens instead of hardcoded colors.

Hardcoded color values like #007bff and #666 may not align with the design system. If @raystack/apsara provides CSS variables or tokens, consider using them for consistency.

Also applies to: 18-18, 35-35

Comment on lines +11 to +31
export function SheetHeader({ title, onClick, "data-testid": dataTestId }: SheetHeaderProps) {
return (
<Flex justify="between" style={styles.header}>
<Text size={4} style={{ fontWeight: "500" }}>
{title}
</Text>
<Cross1Icon
onClick={onClick}
style={{ cursor: "pointer" }}
data-testid={dataTestId ?? "admin-close-btn"}
/>
</Flex>
);
}

const styles: { header: CSSProperties } = {
header: {
padding: "18px 32px",
borderBottom: "1px solid var(--rs-color-border-base-primary)",
},
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the SheetHeader.tsx file
find . -name "SheetHeader.tsx" -type f | head -20

Repository: raystack/frontier

Length of output: 103


🏁 Script executed:

# Search for Cross1Icon component definition
find . -type f -name "*.tsx" -o -name "*.ts" | xargs grep -l "Cross1Icon" | head -10

Repository: raystack/frontier

Length of output: 408


🏁 Script executed:

# Look for any accessibility-related attributes or patterns in the file
rg "role|aria-|keyboard" web/lib/admin/components/SheetHeader.tsx -A 3 -B 3

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Read the SheetHeader.tsx file
cat -n web/lib/admin/components/SheetHeader.tsx

Repository: raystack/frontier

Length of output: 1078


🏁 Script executed:

# Search for Cross1Icon import and definition
rg "import.*Cross1Icon|from.*@radix" web/lib/admin/components/SheetHeader.tsx -A 2 -B 2

Repository: raystack/frontier

Length of output: 204


🏁 Script executed:

# Look for Cross1Icon in the entire codebase to understand its source
rg "Cross1Icon" --type tsx --type ts -B 2 | head -50

Repository: raystack/frontier

Length of output: 88


🏁 Script executed:

# Search for other uses of Cross1Icon or similar icon patterns in the codebase
rg "Cross1Icon|Icon.*onClick" -A 3 -B 1 | head -60

Repository: raystack/frontier

Length of output: 4304


🏁 Script executed:

# Look for button patterns with icons in the codebase
rg "<button.*aria-label|type=\"button\".*Icon" -A 2 -B 2 | head -80

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Check if there are accessibility patterns or components for icon buttons
rg "IconButton|close.*button|aria-label" web/lib/admin/components -A 2 -B 2

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Search for IconButton component definition and usage
rg "IconButton" web/ -A 5 -B 2 | head -100

Repository: raystack/frontier

Length of output: 7568


🏁 Script executed:

# Check if `@raystack/apsara` has IconButton documentation or types
find . -name "*.tsx" -o -name "*.ts" | xargs grep -l "export.*IconButton\|from.*apsara.*IconButton" | head -10

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Look for tests related to SheetHeader
find . -name "*SheetHeader*test*" -o -name "*SheetHeader*.spec.*"

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Search for any related accessibility tests or patterns
rg "admin-close-btn|testid.*close" -A 3 -B 3 | head -80

Repository: raystack/frontier

Length of output: 988


🏁 Script executed:

# Check the imports available in SheetHeader.tsx and if IconButton can be imported
rg "from.*@raystack/apsara" web/lib/admin/components/SheetHeader.tsx

Repository: raystack/frontier

Length of output: 107


🏁 Script executed:

# Look at how IconButton is imported in other files to understand the pattern
rg "import.*IconButton.*@raystack/apsara" web/apps/admin/src/ -B 2 | head -30

Repository: raystack/frontier

Length of output: 816


🏁 Script executed:

# Check if SheetHeader component is used in tests and what accessibility expectations exist
find . -path "*/test*" -o -path "*/spec*" | xargs grep -l "SheetHeader\|admin-close-btn" 2>/dev/null

Repository: raystack/frontier

Length of output: 45


🏁 Script executed:

# Check if IconButton can be imported and used in SheetHeader
grep -r "export.*IconButton" web/lib/admin/ 2>/dev/null | head -20

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Look at an actual IconButton usage to understand required props
rg "IconButton" web/apps/admin/src/pages/invoices/list/navbar.tsx -A 5 -B 2 | head -40

Repository: raystack/frontier

Length of output: 638


🏁 Script executed:

# Check if there's a pattern of using native button vs IconButton in headers/close actions
rg "<button.*close|<IconButton.*close" -A 3 -B 3 | head -60

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Verify `@raystack/apsara` exports IconButton from web/lib
find web/lib -name "*.ts" -o -name "*.tsx" | xargs grep "export.*IconButton" 2>/dev/null

Repository: raystack/frontier

Length of output: 45


Use IconButton for the close action to meet accessibility requirements.
The Cross1Icon lacks button semantics and an accessible name, making it inaccessible to keyboard users. Use the IconButton component from @raystack/apsara (already available in this file's dependencies and used throughout the codebase) with an aria-label instead of attaching onClick directly to the icon.

♿ Proposed fix
 export function SheetHeader({ title, onClick, "data-testid": dataTestId }: SheetHeaderProps) {
   return (
     <Flex justify="between" style={styles.header}>
       <Text size={4} style={{ fontWeight: "500" }}>
         {title}
       </Text>
-      <Cross1Icon
+      <IconButton
+        aria-label="Close"
         onClick={onClick}
-        style={{ cursor: "pointer" }}
         data-testid={dataTestId ?? "admin-close-btn"}
-      />
+      >
+        <Cross1Icon />
+      </IconButton>
     </Flex>
   );
 }

Also update the import to include IconButton:

-import { Flex, Text } from "@raystack/apsara";
+import { Flex, Text, IconButton } from "@raystack/apsara";
🧰 Tools
🪛 GitHub Check: JS SDK Lint

[warning] 17-17:
Elements with an onClick handler must have a data-test-id attribute

🤖 Prompt for AI Agents
In `@web/lib/admin/components/SheetHeader.tsx` around lines 11 - 31, Replace the
clickable Cross1Icon in SheetHeader with the IconButton component from
`@raystack/apsara` so the close control has proper button semantics and an
accessible name; update the import to include IconButton, render IconButton
(passing the Cross1Icon as its icon prop or children), move the onClick handler
from Cross1Icon to IconButton, add aria-label (e.g., "Close sheet") and keep
data-testid usage (use dataTestId or default "admin-close-btn") to preserve
tests.

Comment on lines +36 to +40
const handleRowClick = useCallback(
(role: Role) =>
onSelectRole ? onSelectRole(role.id ?? "") : setInternalRoleId(role.id ?? undefined),
[onSelectRole]
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent handling of undefined role ID.

Line 38 converts role.id to empty string (role.id ?? ""), while line 38 in the else branch uses role.id ?? undefined. This inconsistency could cause subtle bugs if consumers compare selectedRoleId values.

🐛 Proposed fix for consistency
   const handleRowClick = useCallback(
     (role: Role) =>
-      onSelectRole ? onSelectRole(role.id ?? "") : setInternalRoleId(role.id ?? undefined),
+      onSelectRole ? onSelectRole(role.id ?? "") : setInternalRoleId(role.id),
     [onSelectRole]
   );

Note: role.id is already string | undefined, so ?? undefined is redundant.

📝 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
const handleRowClick = useCallback(
(role: Role) =>
onSelectRole ? onSelectRole(role.id ?? "") : setInternalRoleId(role.id ?? undefined),
[onSelectRole]
);
const handleRowClick = useCallback(
(role: Role) =>
onSelectRole ? onSelectRole(role.id ?? "") : setInternalRoleId(role.id),
[onSelectRole]
);
🤖 Prompt for AI Agents
In `@web/lib/admin/views/roles/index.tsx` around lines 36 - 40, handleRowClick
inconsistently maps Role.id to "" in the onSelectRole branch but to undefined in
the setInternalRoleId branch; make both branches pass the same type (prefer
leaving id as-is or using undefined consistently). Update the handleRowClick
callback to call onSelectRole(role.id) (or onSelectRole(role.id ?? undefined) if
callback expects string|undefined) and setInternalRoleId(role.id) so both
branches use role.id (string | undefined) consistently; reference the
handleRowClick function, the onSelectRole prop, setInternalRoleId, and the
Role.id field when making the change.

Comment on lines +2 to +7
const extendsList = [
'next',
'prettier',
"eslint:recommended",
'plugin:test-selectors/recommended'
];
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if turbo ESLint config is still referenced elsewhere or if there are turbo-specific rules in use.

# Search for any references to eslint-config-turbo or turbo eslint rules
rg -n "turbo" --type js --type json -g "!node_modules" -g "!*.lock"

Repository: raystack/frontier

Length of output: 843


🏁 Script executed:

cat -n web/tools/eslint-config/index.js

Repository: raystack/frontier

Length of output: 660


🏁 Script executed:

cat -n web/apps/client-demo/.eslintrc.js

Repository: raystack/frontier

Length of output: 242


Remove the unused eslint-config-turbo dependency or restore 'turbo' to the extends list.

The removal of 'turbo' from the extends list is problematic: web/tools/eslint-config/package.json still lists eslint-config-turbo as a dependency, and web/apps/client-demo/.eslintrc.js actively configures the turbo/no-undeclared-env-vars rule. Either restore 'turbo' to the extends list or remove the unused dependency from package.json.

🤖 Prompt for AI Agents
In `@web/tools/eslint-config/index.js` around lines 2 - 7, The extendsList array
currently omits 'turbo' while package.json still lists eslint-config-turbo and
client-demo/.eslintrc.js uses the turbo/no-undeclared-env-vars rule; either
re-add 'turbo' into the extendsList (add 'turbo' to the extendsList constant so
the turbo rules are applied) or remove the eslint-config-turbo dependency from
web/tools/eslint-config/package.json and update client-demo/.eslintrc.js to stop
referencing turbo rules; locate and edit the extendsList constant and
package.json dependency to keep them consistent with the .eslintrc.js usage.

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.

3 participants