Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
67ee922
feat: add tab navigation for app details and deals in AppsRoute compo…
ErwanDecoster Oct 15, 2025
e2de601
feat: add AppAccessTable component and integrate into AppsRoute
ErwanDecoster Oct 16, 2025
ca724b5
feat: enhance AppAccessTable and AppDealsTable with loading and outda…
ErwanDecoster Oct 16, 2025
aeae164
feat: rename columns to appColumns and remove app address and price c…
ErwanDecoster Oct 16, 2025
10c2da9
feat: add tab navigation for dataset details, deals, and access in Da…
ErwanDecoster Oct 16, 2025
df51a0e
feat: integrate loading and outdated state management in DatasetDeals…
ErwanDecoster Oct 16, 2025
6970d14
feat: add DatasetAccessTable component and integrate it into Datasets…
ErwanDecoster Oct 16, 2025
691c276
feat: add tab navigation for workerpool details, deals, and access
ErwanDecoster Oct 16, 2025
9a9ac27
feat: enhance WorkerpoolDealsTable with loading and outdated state ma…
ErwanDecoster Oct 16, 2025
f26634d
feat: add WorkerpoolAccessTable component and integrate it into Worke…
ErwanDecoster Oct 16, 2025
d05f864
feat: refactor loading and outdated state management in access and de…
ErwanDecoster Oct 16, 2025
6a02688
feat: add access tables for apps, datasets, and workerpools on addres…
ErwanDecoster Oct 17, 2025
f93cdc2
fix: correct import path for WorkerpoolAccessTable component
ErwanDecoster Oct 17, 2025
f340188
refactor: remove console logs from access data fetching functions
ErwanDecoster Oct 17, 2025
d35aa68
feat: enhance pagination logic to display all pages for 7 or fewer to…
ErwanDecoster Oct 17, 2025
4efb46f
feat: update pagination logic to support mobile-first design and dyna…
ErwanDecoster Oct 17, 2025
6332132
feat: update access data fetching logic to support pagination and tot…
ErwanDecoster Oct 17, 2025
2e677ba
fix: prevent rendering of pagination controls for invalid states
ErwanDecoster Oct 17, 2025
83f837e
refactor: prettier
ErwanDecoster Oct 17, 2025
66d27df
fix: stabilize pagination rendering during lading state
ErwanDecoster Oct 17, 2025
198d0ed
fix: normalize case for order restrictions in CopyButton components
ErwanDecoster Oct 17, 2025
370ab44
Merge branch 'main' into feature/add-assets-order
ErwanDecoster Oct 17, 2025
53f512f
fix: useTabParam() name in dataset
ErwanDecoster Oct 17, 2025
985787e
fix: correct error message wording in loading alerts across multiple …
ErwanDecoster Oct 17, 2025
2f58900
Merge branch 'feature/add-assets-order' of https://github.com/iExecBl…
ErwanDecoster Oct 17, 2025
f704e37
feat: add accessibility attributes to buttons in CopyButton, Navbar, …
ErwanDecoster Oct 17, 2025
f5e75ce
feat: add accessibility attributes to ChainLink and Button components…
ErwanDecoster Oct 17, 2025
6693077
feat: add accessibility attributes to social links in Footer and Bloc…
ErwanDecoster Oct 17, 2025
e87be49
feat: enhance accessibility in SearcherBar component; add ARIA roles …
ErwanDecoster Oct 17, 2025
b4eaf7f
Merge branch 'main' into feature/better-accessibility
ErwanDecoster Dec 19, 2025
590531a
fix: fix typo
ErwanDecoster Dec 19, 2025
cc1f0b0
fix: improve accessibility roles in Navbar and Tabs components
ErwanDecoster Dec 19, 2025
0176a02
Merge branch 'feature/better-accessibility' of https://github.com/iEx…
ErwanDecoster Dec 19, 2025
f1f5e93
fix: update package-lock file
ErwanDecoster Dec 19, 2025
7bcdeb6
fix: remove unnecessary id attributes for accessibility improvements
ErwanDecoster Jan 7, 2026
6e408b2
fix: remove useless id attribute or ensure uniqueness. Also fix acess…
Christophe-iExec Jan 28, 2026
e0bcb11
fix: remove useless implicite role=searchbox and invalid tabIndex
Christophe-iExec Jan 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,628 changes: 2,300 additions & 328 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"graphql": "^16.11.0",
"iexec": "^8.18.0",
"iexec": "^8.20.0",
"lucide-react": "^0.536.0",
"prettier-plugin-tailwindcss": "^0.6.14",
"react": "^19.2.0",
Expand Down
3 changes: 3 additions & 0 deletions src/components/CopyButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ const CopyButton = ({
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
className="hover:before:bg-muted active:before:bg-secondary relative z-0 -mx-1 -my-1 flex items-center gap-1 px-1 py-1 transition-colors before:absolute before:inset-0 before:-z-10 before:rounded-lg before:duration-200 active:before:scale-x-[0.98] active:before:scale-y-[0.94]"
id="copy-button"
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
Comment thread
ErwanDecoster marked this conversation as resolved.
Outdated
type="button"
aria-label="Copy"
>
{buttonText && <span className="mr-1 text-sm">{buttonText}</span>}
<Copy className="size-4 flex-none" />
Expand Down
38 changes: 30 additions & 8 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,40 @@ import { Button } from './ui/button';

function SocialLinksItems({ className }: { className?: string }) {
const socialLinks = [
{ href: 'https://twitter.com/iEx_ec', icon: <SiX size={16} /> },
{ href: 'https://discord.gg/pbt9m98wnU', icon: <SiDiscord size={16} /> },
{ href: 'https://t.me/iexec_rlc_official', icon: <SiTelegram size={16} /> },
{
href: 'https://twitter.com/iEx_ec',
icon: <SiX size={16} />,
arialLabel: 'Twitter',
Comment thread
ErwanDecoster marked this conversation as resolved.
Outdated
},
{
href: 'https://discord.gg/pbt9m98wnU',
icon: <SiDiscord size={16} />,
ariaLabel: 'Discord',
},
{
href: 'https://t.me/iexec_rlc_official',
icon: <SiTelegram size={16} />,
ariaLabel: 'Telegram',
},
{
href: 'https://www.youtube.com/channel/UCwWxZWvKVHn3CXnmDooLWtA',
icon: <SiYoutube size={16} />,
ariaLabel: 'YouTube',
},
{
href: 'https://www.linkedin.com/company/iex.ec/',
icon: <Linkedin size={16} />,
ariaLabel: 'LinkedIn',
},
{
href: 'https://medium.com/iex-ec',
icon: <SiMedium size={16} />,
ariaLabel: 'Medium',
},
{ href: 'https://medium.com/iex-ec', icon: <SiMedium size={16} /> },
];
return (
<div className={cn('flex', className)}>
{socialLinks.map(({ href, icon }, idx) => (
{socialLinks.map(({ href, icon, ariaLabel }, idx) => (
<Button
key={idx}
asChild
Expand All @@ -41,7 +59,7 @@ function SocialLinksItems({ className }: { className?: string }) {
href={href}
target="_blank"
rel="noopener noreferrer"
aria-label="Social link"
aria-label={ariaLabel}
>
{icon}
</a>
Expand Down Expand Up @@ -78,8 +96,12 @@ export function Footer({ className }: { className?: string }) {
)}
>
<div className="flex flex-col items-center justify-between gap-10 xl:flex-row">
<ChainLink to="/" className="flex items-center gap-2 font-mono">
<img src={iExecLogo} width="25" height="25" alt="iExec logo" />
<ChainLink
to="/"
aria-label="Home"
className="flex items-center gap-2 font-mono"
>
<img src={iExecLogo} width="25" height="25" alt="" />
<span>iExec Explorer</span>
</ChainLink>

Expand Down
2 changes: 1 addition & 1 deletion src/components/ModeToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function ModeToggle() {
size="none"
role="radio"
aria-checked={selected}
aria-label={label}
aria-label={`Toggle ${label} mode`}
title={label}
className={cn(
'text-foreground hover:bg-muted p-1',
Expand Down
71 changes: 60 additions & 11 deletions src/components/PaginatedNavigation.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useRef } from 'react';
import {
Pagination,
PaginationContent,
Expand All @@ -19,24 +20,70 @@ export const PaginatedNavigation = ({
totalPages,
onPageChange,
}: PaginationControlsProps) => {
// Keep stable totalPages to prevent pagination from disappearing during loading
const lastValidTotalPagesRef = useRef<number>(1);

// Only update the ref if we have a valid totalPages (> 0)
if (totalPages > 0) {
lastValidTotalPagesRef.current = totalPages;
}

const stableTotalPages = lastValidTotalPagesRef.current;

// Don't render pagination if no pages or invalid state
if (!stableTotalPages || stableTotalPages <= 0 || currentPage <= 0) {
return null;
}

const generatePages = () => {
const pages: (number | 'ellipsis')[] = [];

if (totalPages <= 5) {
for (let i = 1; i <= totalPages; i++) {
// Mobile-first approach: show fewer pages on small screens
const isMobile = typeof window !== 'undefined' && window.innerWidth < 640;
const maxVisiblePages = isMobile ? 3 : 7;

if (stableTotalPages <= maxVisiblePages) {
// Show all pages if within limit
for (let i = 1; i <= stableTotalPages; i++) {
pages.push(i);
}
} else if (currentPage <= 3) {
for (let i = 1; i <= Math.min(currentPage + 2, totalPages); i++) {
pages.push(i);
} else if (isMobile) {
// Mobile: simplified pagination - only show current and neighbors
if (currentPage === 1) {
// At start: 1 2 ... last
pages.push(1, 2, 'ellipsis', stableTotalPages);
} else if (currentPage === stableTotalPages) {
// At end: 1 ... (last-1) last
pages.push(1, 'ellipsis', stableTotalPages - 1, stableTotalPages);
} else {
// Middle: 1 ... current ... last
pages.push(1, 'ellipsis', currentPage, 'ellipsis', stableTotalPages);
}
} else {
// Desktop: full pagination logic
pages.push(1);
pages.push('ellipsis');

const maxPage = Math.min(currentPage + 2, totalPages);
for (let i = currentPage; i <= maxPage; i++) {
pages.push(i);
if (currentPage <= 3) {
// Near beginning: 1 2 3 4 ... last
for (let i = 2; i <= 4; i++) {
pages.push(i);
}
pages.push('ellipsis');
pages.push(stableTotalPages);
} else if (currentPage >= stableTotalPages - 2) {
// Near end: 1 ... (last-3) (last-2) (last-1) last
pages.push('ellipsis');
for (let i = stableTotalPages - 3; i <= stableTotalPages; i++) {
pages.push(i);
}
} else {
// In middle: 1 ... (current-1) current (current+1) ... last
pages.push('ellipsis');
for (let i = currentPage - 1; i <= currentPage + 1; i++) {
pages.push(i);
}
pages.push('ellipsis');
pages.push(stableTotalPages);
}
}

Expand All @@ -50,7 +97,7 @@ export const PaginatedNavigation = ({
};

const handleNext = () => {
if (currentPage < totalPages) onPageChange(currentPage + 1);
if (currentPage < stableTotalPages) onPageChange(currentPage + 1);
};

return (
Expand Down Expand Up @@ -86,7 +133,9 @@ export const PaginatedNavigation = ({
<PaginationNext
onClick={handleNext}
className={
currentPage === totalPages ? 'pointer-events-none opacity-50' : ''
currentPage === stableTotalPages
? 'pointer-events-none opacity-50'
: ''
}
/>
</PaginationItem>
Expand Down
1 change: 1 addition & 0 deletions src/components/SmartLinkGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export default function SmartLinkGroup({
href={`${getBlockExplorerUrl(chainId)}/${blockExplorerPath[type]}`}
target="_blank"
rel="noopener noreferrer"
aria-label="Open in Block Explorer"
>
<ExternalLink className="text-foreground" />
</a>
Expand Down
1 change: 1 addition & 0 deletions src/components/navbar/AddressChip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export function AddressChip({ address }: { address: string }) {
<Button
className="dark:bg-popover bg-primary-foreground hover:bg-muted text-primary dark:text-brand duration-300"
variant="secondary"
aria-label="Copy connected wallet address"
onClick={handleCopy}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
Expand Down
22 changes: 18 additions & 4 deletions src/components/navbar/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ export function Navbar() {

return (
<nav className="flex items-center justify-between py-6">
<ChainLink to="/" className="-m-2 flex items-center gap-2 p-2 font-mono">
<img src={iExecLogo} width="25" height="25" alt="iExec logo" />
<ChainLink
to="/"
aria-label="Home"
className="-m-2 flex items-center gap-2 p-2 font-mono"
>
<img src={iExecLogo} width="25" height="25" alt="" />
Comment thread
ErwanDecoster marked this conversation as resolved.
<span className="hidden lg:block">iExec Explorer</span>
</ChainLink>
<div className="mr-8 flex items-center gap-4 md:mr-0">
Expand Down Expand Up @@ -50,6 +54,8 @@ export function Navbar() {

<button
type="button"
id="logout-button"
aria-label="Logout"
className="hover:drop-shadow-link-hover p-1"
onClick={() => logout()}
>
Expand All @@ -74,6 +80,7 @@ export function Navbar() {
className="absolute -inset-2 size-10 cursor-pointer appearance-none bg-transparent"
name="menu"
id="menu"
aria-label="Toggle navigation menu"
checked={isMenuOpen}
readOnly
/>
Expand All @@ -84,15 +91,22 @@ export function Navbar() {

<div className="border-secondary bg-background pointer-events-auto fixed inset-y-0 left-0 z-10 flex w-full -translate-x-full flex-col overflow-auto rounded-r-3xl border-r px-6 pt-6 duration-200 group-has-[:checked]:translate-x-0 lg:w-[255px] lg:translate-x-0">
<div className="-m-2 mr-6 flex items-center justify-between gap-2 py-2 pl-2">
<ChainLink to="/" className="font-mono" onClick={handleMenuToggle}>
<img src={iExecLogo} width="25" height="25" alt="iExec logo" />
<ChainLink
to="/"
aria-label="Home"
className="font-mono"
onClick={handleMenuToggle}
>
<img src={iExecLogo} width="25" height="25" alt="" />
</ChainLink>
{isConnected ? (
<div className="flex max-w-[1260px] items-center gap-2">
<AddressChip address={userAddress!} />

<button
type="button"
id="logout-button"
aria-label="Logout"
className="hover:drop-shadow-link-hover p-1"
onClick={() => logout()}
>
Expand Down
1 change: 1 addition & 0 deletions src/modules/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export function Tabs({
key={label}
data-tab-index={index}
variant="link"
role="radio"
Comment thread
ErwanDecoster marked this conversation as resolved.
Outdated
size={'none'}
onClick={() => {
if (!isDisabled) onTabChange(index);
Expand Down
62 changes: 62 additions & 0 deletions src/modules/access/appColumns.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ColumnDef } from '@tanstack/react-table';
import { PublishedApporder } from 'iexec/IExecOrderbookModule';
import CopyButton from '@/components/CopyButton';
import { truncateAddress } from '@/utils/truncateAddress';

export const columns: ColumnDef<PublishedApporder>[] = [
{
accessorKey: 'order.datasetrestrict',
header: 'Dataset Restriction',
cell: ({ row }) => (
<CopyButton
displayText={truncateAddress(
row.original.order.datasetrestrict.toLowerCase(),
{
startLen: 8,
}
)}
textToCopy={row.original.order.datasetrestrict.toLowerCase()}
/>
),
},
{
accessorKey: 'order.requesterrestrict',
header: 'Requester Restriction',
cell: ({ row }) => (
<CopyButton
displayText={truncateAddress(
row.original.order.requesterrestrict.toLowerCase(),
{
startLen: 8,
}
)}
textToCopy={row.original.order.requesterrestrict.toLowerCase()}
/>
),
},
{
accessorKey: 'order.workerpoolrestrict',
header: 'Workerpool Restriction',
cell: ({ row }) => (
<CopyButton
displayText={truncateAddress(
row.original.order.workerpoolrestrict.toLowerCase(),
{
startLen: 8,
}
)}
textToCopy={row.original.order.workerpoolrestrict.toLowerCase()}
/>
),
},
{
accessorKey: 'order.volume',
header: 'Volume',
cell: ({ row }) => <span>{row.original.order.volume}</span>,
},
{
accessorKey: 'remaining',
header: 'Remaining',
cell: ({ row }) => <span>{row.original.remaining}</span>,
},
];
Loading
Loading