diff --git a/locales/en/common.json b/locales/en/common.json index 1e9645cf02..983dc9be0f 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -11,6 +11,7 @@ "BETA": "Beta", "CANCEL": "Cancel", "CARD_TYPE": "Card type", + "CAUTION": "Caution", "CLEAN": "Clean", "CLEAR": "Clear", "CLEAR_FILTERS": "Clear all filters", @@ -68,11 +69,15 @@ "SHOW_LESS": "Show less", "SHOW_MORE": "Show more", "SOMETHING_WENT_WRONG": "Something went wrong", + "STATUS": "Status", "SUBMIT": "Submit", "SUBMITTING": "Submitting", "SUGGESTED": "Suggested", + "TARGET": "Target", "TEMPLATE": "Template", + "TEST": "Test", "TIME": "Time", + "UNKNOWN_ERROR": "Unknown error", "UPLOAD": "Upload", "USER_SUBMITTED": "User-submitted", "VIEW": "View", diff --git a/locales/en/public.json b/locales/en/public.json index d4597195c0..949b310d55 100644 --- a/locales/en/public.json +++ b/locales/en/public.json @@ -181,6 +181,20 @@ "TEMPLATE_HINT": "A Template must be selected.", "WARNING_NO_MATCH": "Warning: Match Expression matches no targets." }, + "CredentialTestTable": { + "ARIA_LABELS": { + "STATUS_POPOVER": "Test Result Details ({{connectUrl}})", + "STATUS_SELECT": "test-status-select", + "TOOLBAR": "credential-test-table-toolbar" + }, + "CLEAR_AND_TRY_AGAIN": "Clear Match Expression and try again.", + "ENTER_ANOTHER": "Enter another Match Expression.", + "NO_TARGET_MATCHED": "No Targets Matched", + "SEARCH_PLACEHOLDER": "Find by connection URL or alias...", + "TEST_ALL": "Test All", + "TEST_ALL_TOOLTIP": "Test credentials against all matching targets.", + "TEST_FAILED": "Test failed" + }, "Dashboard": { "ADD_CARD_HELPER_TEXT": "Choose a card type to add to your Dashboard. Some cards require additional configuration.", "CARD_CATALOG_DESCRIPTION": "Cards added to this Dashboard Layout present information at a glance about the selected target. The layout is preserved for all targets viewed on this client.", @@ -317,6 +331,12 @@ "MATCH_EXPRESSION_VISUALIZER": { "TITLE": "Match Expression visualizer" }, + "MatchedTargetsTable": { + "ARIA_LABELS": { + "TABLE": "matched-targets-table" + }, + "NO_TARGET_MATCHED": "No Targets Matched" + }, "MeridiemPicker": { "ARIA_LABELS": { "LISTBOX": "Select AM or PM" @@ -447,12 +467,16 @@ "StoredCredentials": { "ARIA_LABELS": { "Add": "add-credential", - "Delete": "delete-selected-credential" + "Delete": "delete-selected-credential", + "FILTER_CHECKBOX": "select-all", + "ROW_CHECKBOX": "credentials-table-row-{{index}}", + "TABLE": "stored-credentials" }, "AT_LEAST_ONE_MATCH": "At least 1 match", "CARD_DESCRIPTION": "Credentials that Cryostat uses to connect to Cryostat agents or target JVMs over JMX are stored in encrypted storage managed by the Cryostat server.", "CARD_TITLE": "Stored Credentials", "CARD_TITLE_POPOVER_HEADER": "JMX Authentication", + "NO_CREDENTIAL_TITLE": "No Stored Credentials", "NO_MATCH": "No Match", "SEARCH_PLACEHOLDER": "Find by Match Expression..." }, diff --git a/src/app/SecurityPanel/Credentials/CredentialTestTable.tsx b/src/app/SecurityPanel/Credentials/CredentialTestTable.tsx index 70385490c6..8150a0b80f 100644 --- a/src/app/SecurityPanel/Credentials/CredentialTestTable.tsx +++ b/src/app/SecurityPanel/Credentials/CredentialTestTable.tsx @@ -59,6 +59,7 @@ import { } from '@patternfly/react-table'; import _ from 'lodash'; import * as React from 'react'; +import { useTranslation } from 'react-i18next'; import { catchError, combineLatest, of, switchMap, tap } from 'rxjs'; import { TestPoolContext, useAuthCredential } from './utils'; @@ -81,6 +82,7 @@ const tableColumns: TableColumn[] = [ export interface CredentialTestTableProps {} export const CredentialTestTable: React.FC = ({ ...props }) => { + const { t } = useTranslation(); const addSubscription = useSubscriptions(); const context = React.useContext(ServiceContext); const matchExprService = useMatchExpressionSvc(); @@ -143,9 +145,9 @@ export const CredentialTestTable: React.FC = ({ ...pro - + @@ -157,13 +159,13 @@ export const CredentialTestTable: React.FC = ({ ...pro } - headingLevel="h3" + headingLevel="h4" /> {`${ - matchedExpr === '' ? 'Enter another' : 'Clear' - } Match Expression and try again.`} + matchedExpr === '' ? t('CredentialTestTable.ENTER_ANOTHER') : t('CredentialTestTable.CLEAR_AND_TRY_AGAIN') + }`} ); @@ -207,6 +209,7 @@ export const CredentialTestRow: React.FC = ({ searchText = '', ...props }) => { + const { t } = useTranslation(); const [status, setStatus] = React.useState({ state: CredentialTestState.NO_STATUS, error: undefined, @@ -255,21 +258,31 @@ export const CredentialTestRow: React.FC = ({ return isShowed ? ( - - + @@ -310,6 +323,7 @@ const CredentialToolbar: React.FC = ({ searchText, ...props }) => { + const { t } = useTranslation(); const [credential] = useAuthCredential(); const [disableTest, setDisableTest] = React.useState(false); @@ -332,13 +346,19 @@ const CredentialToolbar: React.FC = ({ }, [filters, searchText, credential, setDisableTest, matchedTargets]); return ( - + onSearch(value)} + placeholder={t('CredentialTestTable.SEARCH_PLACEHOLDER')} value={searchText} + style={{ minWidth: '27ch' }} /> @@ -346,9 +366,9 @@ const CredentialToolbar: React.FC = ({ - + @@ -363,6 +383,7 @@ interface StatusFilterProps { } const StatusFilter: React.FC = ({ onChange, filters, ...props }) => { + const { t } = useTranslation(); const [isOpen, setIsOpen] = React.useState(false); const handleToggle = React.useCallback(() => setIsOpen((old) => !old), [setIsOpen]); @@ -377,7 +398,7 @@ const StatusFilter: React.FC = ({ onChange, filters, ...props const toggle = React.useCallback( (toggleRef: React.Ref) => ( - Status + {t('STATUS', { ns: 'common' })} ), [handleToggle, isOpen], @@ -386,7 +407,7 @@ const StatusFilter: React.FC = ({ onChange, filters, ...props return (
Target{t('TARGET', { ns: 'common' })} - Status + {t('STATUS', { ns: 'common' })}
{!target.alias ? target.connectUrl : `${target.alias} (${target.connectUrl})`} + + {!target.alias || target.alias === target.connectUrl + ? target.connectUrl + : `${target.alias} (${target.connectUrl})`} + {loading ? ( ) : status.state === CredentialTestState.INVALID || status.state === CredentialTestState.NA ? ( : } - headerContent={
{status.state === CredentialTestState.INVALID ? 'Test failed' : 'Caution'}
} - bodyContent={
{status.error?.message || 'Unknown error'}
} + headerContent={ +
+ {status.state === CredentialTestState.INVALID + ? t('CredentialTestTable.TEST_FAILED') + : t('CAUTION', { ns: 'common' })} +
+ } + bodyContent={
{status.error?.message || t('UNKNOWN_ERROR', { ns: 'common' })}
} appendTo={portalRoot} >
+
{tableColumns.map(({ title }, index) => ( diff --git a/src/app/SecurityPanel/Credentials/StoredCredentials.tsx b/src/app/SecurityPanel/Credentials/StoredCredentials.tsx index 0d82b0134b..968cbef724 100644 --- a/src/app/SecurityPanel/Credentials/StoredCredentials.tsx +++ b/src/app/SecurityPanel/Credentials/StoredCredentials.tsx @@ -396,7 +396,7 @@ export const StoredCredentials = () => { onChange={(_event, checked: boolean) => handleRowCheck(checked)} isChecked={isChecked} id={`credentials-table-row-${idx}-check`} - aria-label={`credentials-table-row-${idx}-check`} + aria-label={t('StoredCredentials.ARIA_LABELS.ROW_CHECKBOX', { index: idx })} />
@@ -463,11 +463,7 @@ export const StoredCredentials = () => { - No {tableTitle} {searchText !== '' ? 'Found' : ''} - - } + titleText={<>{t('StoredCredentials.NO_CREDENTIAL_TITLE')}} icon={} headingLevel="h4" /> @@ -478,7 +474,7 @@ export const StoredCredentials = () => { } else { content = ( <> - +
@@ -557,7 +553,7 @@ export const CheckBoxActions: React.FC = ({ ,