diff --git a/app/docker/views/images/build/buildimage.html b/app/docker/views/images/build/buildimage.html index d6e09e1ad..928a19393 100644 --- a/app/docker/views/images/build/buildimage.html +++ b/app/docker/views/images/build/buildimage.html @@ -209,7 +209,7 @@ Output -
+            
               

{{ line }}

No build output available.

diff --git a/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list-item/helm-templates-list-item.html b/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list-item/helm-templates-list-item.html index 17cf83b81..43658b833 100644 --- a/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list-item/helm-templates-list-item.html +++ b/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list-item/helm-templates-list-item.html @@ -1,5 +1,5 @@ -
+
diff --git a/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.html b/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.html index 7a622c042..2fb7cce11 100644 --- a/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.html +++ b/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.html @@ -30,7 +30,7 @@ >
-
+
) { const baseClasses = - 'flex w-fit items-center !text-xs font-medium rounded-full px-2 py-0.5'; + 'inline-flex w-fit items-center !text-xs font-medium rounded-full px-2 py-0.5'; return ( - + {children} ); diff --git a/app/react/components/Blocklist/BlocklistItem.tsx b/app/react/components/Blocklist/BlocklistItem.tsx index 15e9e6d57..d4ff4a1c1 100644 --- a/app/react/components/Blocklist/BlocklistItem.tsx +++ b/app/react/components/Blocklist/BlocklistItem.tsx @@ -28,6 +28,7 @@ export function BlocklistItem({ 'blocklist-item--selected': isSelected, } )} + role="listitem" // eslint-disable-next-line react/jsx-props-no-spreading {...props} > diff --git a/app/react/components/datatables/Datatable.tsx b/app/react/components/datatables/Datatable.tsx index 33354e03b..3d6f4e93a 100644 --- a/app/react/components/datatables/Datatable.tsx +++ b/app/react/components/datatables/Datatable.tsx @@ -188,6 +188,7 @@ export function Datatable({ isLoading={isLoading} onSortChange={handleSortChange} data-cy={dataCy} + aria-label={`${title} table`} /> extends AutomationTestingProps { onSortChange?(colId: string, desc: boolean): void; isLoading?: boolean; emptyContentLabel?: string; + 'aria-label'?: string; } export function DatatableContent({ @@ -20,12 +21,13 @@ export function DatatableContent({ isLoading, emptyContentLabel, 'data-cy': dataCy, + 'aria-label': ariaLabel, }: Props) { const headerGroups = tableInstance.getHeaderGroups(); const pageRowModel = tableInstance.getPaginationRowModel(); return ( - +
{headerGroups.map((headerGroup) => ( diff --git a/app/react/components/datatables/NestedDatatable.tsx b/app/react/components/datatables/NestedDatatable.tsx index 6569435d5..68a4a8ef2 100644 --- a/app/react/components/datatables/NestedDatatable.tsx +++ b/app/react/components/datatables/NestedDatatable.tsx @@ -28,6 +28,8 @@ interface Props { * keyword to filter by */ search?: string; + + 'aria-label'?: string; } export function NestedDatatable({ @@ -39,6 +41,7 @@ export function NestedDatatable({ isLoading, initialSortBy, search, + 'aria-label': ariaLabel, }: Props) { const tableInstance = useReactTable({ columns, @@ -70,6 +73,7 @@ export function NestedDatatable({ isLoading={isLoading} emptyContentLabel={emptyContentLabel} renderRow={(row) => cells={row.getVisibleCells()} />} + aria-label={ariaLabel} /> diff --git a/app/react/components/datatables/SearchBar.tsx b/app/react/components/datatables/SearchBar.tsx index d6985324e..b8dab65ea 100644 --- a/app/react/components/datatables/SearchBar.tsx +++ b/app/react/components/datatables/SearchBar.tsx @@ -42,6 +42,7 @@ export function SearchBar({ onChange={(e) => setSearchValue(e.target.value)} placeholder={placeholder} data-cy={dataCy} + aria-label="Search input" /> {children}
{children}
diff --git a/app/react/components/datatables/TableTitle.tsx b/app/react/components/datatables/TableTitle.tsx index 419979167..446990a2f 100644 --- a/app/react/components/datatables/TableTitle.tsx +++ b/app/react/components/datatables/TableTitle.tsx @@ -23,7 +23,7 @@ export function TableTitle({ <>
-
+

{icon && (
@@ -31,7 +31,7 @@ export function TableTitle({ )} {label} -
+

{children}
diff --git a/app/react/components/datatables/expand-column.tsx b/app/react/components/datatables/expand-column.tsx index ce011991c..d3eccdac9 100644 --- a/app/react/components/datatables/expand-column.tsx +++ b/app/react/components/datatables/expand-column.tsx @@ -17,6 +17,7 @@ export function buildExpandColumn(): ColumnDef { onClick={table.getToggleAllRowsExpandedHandler()} color="none" icon={table.getIsAllRowsExpanded() ? ChevronDown : ChevronUp} + title="Expand all" /> ) ); @@ -32,6 +33,7 @@ export function buildExpandColumn(): ColumnDef { }} color="none" icon={row.getIsExpanded() ? ChevronDown : ChevronUp} + title={row.getIsExpanded() ? 'Collapse' : 'Expand'} /> ), enableColumnFilter: false, diff --git a/app/react/components/form-components/PortainerSelect.tsx b/app/react/components/form-components/PortainerSelect.tsx index 81105652b..19088a377 100644 --- a/app/react/components/form-components/PortainerSelect.tsx +++ b/app/react/components/form-components/PortainerSelect.tsx @@ -4,6 +4,7 @@ import { SelectComponentsConfig, } from 'react-select'; import _ from 'lodash'; +import { AriaAttributes } from 'react'; import { AutomationTestingProps } from '@/types'; @@ -20,7 +21,9 @@ type Options = OptionsOrGroups< GroupBase> >; -interface SharedProps extends AutomationTestingProps { +interface SharedProps + extends AutomationTestingProps, + Pick { name?: string; inputId?: string; placeholder?: string; @@ -87,6 +90,8 @@ export function SingleSelect({ components, isLoading, noOptionsMessage, + isMulti, + ...aria }: SingleProps) { const selectedValue = value || (typeof value === 'number' && value === 0) @@ -111,6 +116,8 @@ export function SingleSelect({ components={components} isLoading={isLoading} noOptionsMessage={noOptionsMessage} + // eslint-disable-next-line react/jsx-props-no-spreading + {...aria} /> ); } @@ -152,6 +159,7 @@ export function MultiSelect({ components, isLoading, noOptionsMessage, + ...aria }: Omit, 'isMulti'>) { const selectedOptions = findSelectedOptions(options, value); return ( @@ -174,6 +182,8 @@ export function MultiSelect({ components={components} isLoading={isLoading} noOptionsMessage={noOptionsMessage} + // eslint-disable-next-line react/jsx-props-no-spreading + {...aria} /> ); } diff --git a/app/react/docker/networks/ListView/NestedNetwordsTable.tsx b/app/react/docker/networks/ListView/NestedNetwordsTable.tsx index 116b23edf..f70802be1 100644 --- a/app/react/docker/networks/ListView/NestedNetwordsTable.tsx +++ b/app/react/docker/networks/ListView/NestedNetwordsTable.tsx @@ -16,5 +16,11 @@ export function NestedNetworksDatatable({ const isSwarm = useIsSwarm(environmentId); const columns = useColumns(isSwarm); - return ; + return ( + + ); } diff --git a/app/react/docker/networks/ListView/columns/name.tsx b/app/react/docker/networks/ListView/columns/name.tsx index 77321a4a9..5da36bb0b 100644 --- a/app/react/docker/networks/ListView/columns/name.tsx +++ b/app/react/docker/networks/ListView/columns/name.tsx @@ -1,6 +1,7 @@ import { truncate } from '@/portainer/filters/filters'; import { Link } from '@@/Link'; +import { Badge } from '@@/Badge'; import { columnHelper } from './helper'; @@ -18,12 +19,9 @@ export const name = columnHelper.accessor('Name', { {truncate(item.Name, 40)} {item.ResourceControl?.System && ( - + System - + )} ); diff --git a/app/react/docker/services/ListView/ServicesDatatable/TasksDatatable/TasksDatatable.tsx b/app/react/docker/services/ListView/ServicesDatatable/TasksDatatable/TasksDatatable.tsx index ce264eba2..5292b6f33 100644 --- a/app/react/docker/services/ListView/ServicesDatatable/TasksDatatable/TasksDatatable.tsx +++ b/app/react/docker/services/ListView/ServicesDatatable/TasksDatatable/TasksDatatable.tsx @@ -24,6 +24,7 @@ export function TasksDatatable({ dataset={dataset} search={search} emptyContentLabel="No task matching filter." + aria-label="Tasks table" /> ); } diff --git a/app/react/docker/volumes/ListView/VolumesDatatable/columns/name.tsx b/app/react/docker/volumes/ListView/VolumesDatatable/columns/name.tsx index 8b3769409..43e381f07 100644 --- a/app/react/docker/volumes/ListView/VolumesDatatable/columns/name.tsx +++ b/app/react/docker/volumes/ListView/VolumesDatatable/columns/name.tsx @@ -108,7 +108,9 @@ function Cell({ )} {item.dangling && ( - Unused + + Unused + )} ); diff --git a/app/react/portainer/HomeView/EnvironmentList/EnvironmentList.tsx b/app/react/portainer/HomeView/EnvironmentList/EnvironmentList.tsx index 7ab88413d..57cd47312 100644 --- a/app/react/portainer/HomeView/EnvironmentList/EnvironmentList.tsx +++ b/app/react/portainer/HomeView/EnvironmentList/EnvironmentList.tsx @@ -212,6 +212,7 @@ export function EnvironmentList({ onClickBrowse, onRefresh }: Props) {
{renderItems( isLoading, diff --git a/app/react/portainer/gitops/RefField/RefField.tsx b/app/react/portainer/gitops/RefField/RefField.tsx index b32c6f9b4..3499d925a 100644 --- a/app/react/portainer/gitops/RefField/RefField.tsx +++ b/app/react/portainer/gitops/RefField/RefField.tsx @@ -31,9 +31,10 @@ export function RefField({ stackId, }: Props) { const [inputValue, updateInputValue] = useStateWrapper(value, onChange); - + const inputId = 'repository-reference-field'; return isBE ? ( @@ -44,6 +45,7 @@ export function RefField({ } > ) : ( @@ -65,6 +68,7 @@ export function RefField({ } > updateInputValue(e.target.value)} placeholder="refs/heads/main" @@ -77,7 +81,8 @@ function Wrapper({ tip, children, errors, -}: PropsWithChildren<{ tip: ReactNode; errors?: string }>) { + inputId, +}: PropsWithChildren<{ tip: ReactNode; errors?: string; inputId: string }>) { return (
@@ -86,7 +91,7 @@ function Wrapper({
diff --git a/app/react/portainer/gitops/RefField/RefSelector.tsx b/app/react/portainer/gitops/RefField/RefSelector.tsx index 4a62a4bc0..0b9e520be 100644 --- a/app/react/portainer/gitops/RefField/RefSelector.tsx +++ b/app/react/portainer/gitops/RefField/RefSelector.tsx @@ -13,12 +13,14 @@ export function RefSelector({ onChange, isUrlValid, stackId, + inputId, }: { model: RefFieldModel; value: string; stackId?: StackId; onChange: (value: string) => void; isUrlValid?: boolean; + inputId: string; }) { const creds = getAuthentication(model); const payload = { @@ -64,6 +66,7 @@ export function RefSelector({ return ( e && onChange(e)} diff --git a/app/react/portainer/templates/app-templates/AppTemplatesList.tsx b/app/react/portainer/templates/app-templates/AppTemplatesList.tsx index 1184f34d6..bdef6b03d 100644 --- a/app/react/portainer/templates/app-templates/AppTemplatesList.tsx +++ b/app/react/portainer/templates/app-templates/AppTemplatesList.tsx @@ -86,7 +86,7 @@ export function AppTemplatesList({ } /> -
+
{pagedTemplates.map((template) => (
)} @@ -71,6 +72,7 @@ export function Filters({ value={listState.types} bindToBody isClearable + aria-label="Type filter" />
)} @@ -83,6 +85,7 @@ export function Filters({ options={orderByFields} placeholder="Sort By" value={listState.sortBy} + aria-label="Sort" />
diff --git a/app/react/portainer/templates/custom-templates/ListView/CustomTemplatesList.tsx b/app/react/portainer/templates/custom-templates/ListView/CustomTemplatesList.tsx index b76c0b924..ae485479b 100644 --- a/app/react/portainer/templates/custom-templates/ListView/CustomTemplatesList.tsx +++ b/app/react/portainer/templates/custom-templates/ListView/CustomTemplatesList.tsx @@ -63,7 +63,7 @@ export function CustomTemplatesList({ )} /> -
+
{pagedTemplates.map((template) => (