Skip to content

Commit

Permalink
chore(pf5): upgrade Security view to Patternfly 5 (#1333)
Browse files Browse the repository at this point in the history
  • Loading branch information
tthvo authored Sep 3, 2024
1 parent d7ce2a5 commit ad5a975
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 160 deletions.
6 changes: 6 additions & 0 deletions locales/en/common.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"ADD": "Add",
"ARCHIVAL_PERIOD": "Archival Period",
"AriaLabels": {
"MAXIMUM_AGE": "Maximum age value",
Expand All @@ -10,6 +11,7 @@
"BETA": "Beta",
"CANCEL": "Cancel",
"CARD_TYPE": "Card type",
"CAUTION": "Caution",
"CLEAN": "Clean",
"CLEAR": "Clear",
"CLEAR_FILTERS": "Clear all filters",
Expand Down Expand Up @@ -69,11 +71,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",
Expand Down
57 changes: 57 additions & 0 deletions locales/en/public.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,20 @@
"POPOVER": "automated-analysis-description-popover"
}
},
"CreateCredentialModal": {
"ARIA_LABELS": {
"HELPER_ICON": "More info for Match Expression field"
},
"EVALUATING_EXPRESSION": "Evaluating Match Expression...",
"FAILING_EVALUATION": "The expression matching failed.",
"MATCH_EXPRESSION_HELPER_TEXT": "Enter a Match Expression. This is a Java-like code snippet that is evaluated against each target application to determine whether the rule should be applied.",
"MATCH_EXPRESSION_HINT_BODY": "Try an expression like:",
"MATCH_EXPRESSION_HINT_MODAL_HEADER": "Match Expression hint",
"MODAL_DESCRIPTION": "Create Stored Credentials for target JVMs. Cryostat will use these credentials to connect to Cryostat agents or target JVMs over JMX (if required).",
"MODAL_TITLE": "Stored Credentials",
"VISUALIZER": "Visualizer",
"WARNING_NO_MATCH": "Warning: Match Expression matches no targets."
},
"CreateRule": {
"ABOUT": "Automated Rules are configurations that instruct Cryostat to create JDK Flight Recordings on matching Target JVM applications. Each Automated Rule specifies parameters for which Event Template to use, how much data should be kept in the application Recording buffer, and how frequently Cryostat should copy the application Recording buffer into Cryostat's own archived storage.",
"ARCHIVAL_PERIOD_HELPER_TEXT": "Time between copies of active Recording data being pulled into Cryostat archive storage.",
Expand All @@ -203,6 +217,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.",
Expand Down Expand Up @@ -302,6 +330,13 @@
"EventTypes": {
"SEARCH_PLACEHOLDER": "Find by name, description, typeId, or description..."
},
"ImportCertificate": {
"CARD_DESCRIPTION": "The following certificates are present in Cryostat&apos's additional trust store. Contact your Cryostat administrator if your application requires a new trusted certificate. You must restart the Cryostat server to reload the certificate store after adding new certificates.",
"CARD_TITLE": "Imported SSL/TLS Certificates",
"CARD_TITLE_POPOVER_HEADER": "JMX over SSL/TLS",
"NO_CERTIFICATE_BODY": "No additional certificates are loaded.",
"NO_CERTIFICATE_TITLE": "No certificates"
},
"JvmDetailsCard": {
"CARD_DESCRIPTION": "Display details about the selected Target JVM.",
"CARD_DESCRIPTION_FULL": "View information such as the connection URL, Labels, and Annotations belonging to the selected Target JVM.",
Expand Down Expand Up @@ -338,6 +373,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"
Expand Down Expand Up @@ -469,6 +510,22 @@
"TABLE": "Shortcuts table"
}
},
"StoredCredentials": {
"ARIA_LABELS": {
"Add": "add-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..."
},
"TargetContextSelector": {
"CLEAR_SELECTION": "Clear selection",
"CREATE_TARGET": "Create Target",
Expand Down
43 changes: 20 additions & 23 deletions src/app/SecurityPanel/Credentials/CreateCredentialModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
} from '@patternfly/react-core';
import { FlaskIcon, HelpIcon, TopologyIcon } from '@patternfly/react-icons';
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { catchError, combineLatest, distinctUntilChanged, interval, map, of, switchMap, tap } from 'rxjs';
import { CredentialTestTable } from './CredentialTestTable';
import { TestRequest } from './types';
Expand All @@ -62,6 +63,7 @@ export const CreateCredentialModal: React.FC<CreateCredentialModalProps> = ({
onPropsSave,
...props
}) => {
const { t } = useTranslation();
const matchExpreRef = React.useRef(new MatchExpressionService());
const loadingRef = React.useRef(new StreamOf(false));
const credentialRef = React.useRef(new StreamOf<AuthCredential>({ username: '', password: '' }));
Expand All @@ -76,15 +78,14 @@ export const CreateCredentialModal: React.FC<CreateCredentialModalProps> = ({

return (
<Modal
appendTo={portalRoot}
isOpen={visible}
tabIndex={0} // enable keyboard-accessible scrolling
variant={ModalVariant.large}
showClose={!inProgress}
className="add-credential-modal"
onClose={onDismiss}
title="Store Credentials"
description="Create Stored Credentials for target JVMs. Cryostat will use these credentials to connect to Cryostat agents or target JVMs over JMX (if required)."
title={t('CreateCredentialModal.MODAL_TITLE')}
description={t('CreateCredentialModal.MODAL_DESCRIPTION')}
>
<SearchExprServiceContext.Provider value={matchExpreRef.current}>
<CredentialContext.Provider value={credentialRef.current}>
Expand Down Expand Up @@ -122,6 +123,7 @@ interface AuthFormProps extends Omit<CreateCredentialModalProps, 'visible'> {
}

export const AuthForm: React.FC<AuthFormProps> = ({ onDismiss, onPropsSave, progressChange, ...props }) => {
const { t } = useTranslation();
const context = React.useContext(ServiceContext);
const addSubscription = useSubscriptions();
const matchExprService = useMatchExpressionSvc();
Expand All @@ -133,7 +135,7 @@ export const AuthForm: React.FC<AuthFormProps> = ({ onDismiss, onPropsSave, prog
const [isDisabled, setIsDisabled] = React.useState(false);
const [evaluating, setEvaluating] = React.useState(false);

const [sampleTarget, setSampleTarget] = React.useState<Target>();
const [sampleTarget, setSampleTarget] = React.useState<Target | undefined>();

const onSave = React.useCallback(
(username: string, password: string) => {
Expand All @@ -159,7 +161,7 @@ export const AuthForm: React.FC<AuthFormProps> = ({ onDismiss, onPropsSave, prog
setMatchExpressionValid(ValidatedOptions.default);
},
}),
context.targets.targets().pipe(tap((ts) => setSampleTarget(ts[0]))),
context.targets.targets().pipe(tap((ts) => (ts && ts.length > 0 ? setSampleTarget(ts[0]) : undefined))),
])
.pipe(
switchMap(([input, targets]) =>
Expand Down Expand Up @@ -216,31 +218,25 @@ export const AuthForm: React.FC<AuthFormProps> = ({ onDismiss, onPropsSave, prog
{...props}
onSave={onSave}
onDismiss={onDismiss}
focus={false}
loading={saving}
isDisabled={isDisabled}
onCredentialChange={setCredential}
>
<FormGroup
label="Match Expression"
label={t('MATCH_EXPRESSION', { ns: 'common' })}
labelIcon={
<Popover
appendTo={portalRoot}
headerContent="Match Expression hint"
headerContent={t('CreateCredentialModal.MATCH_EXPRESSION_HINT_MODAL_HEADER')}
bodyContent={
<>
Try an expression like:
{t('CreateCredentialModal.MATCH_EXPRESSION_HINT_BODY')}
<MatchExpressionHint target={sampleTarget} />
</>
}
hasAutoWidth
>
<Button
variant="plain"
aria-label="More info for Match Expression field"
onClick={(e) => e.preventDefault()}
className="pf-c-form__group-label-help"
>
<Button variant="plain" aria-label={t('CreateCredentialModal.ARIA_LABELS.HELPER_ICON')}>
<HelpIcon />
</Button>
</Popover>
Expand All @@ -253,8 +249,8 @@ export const AuthForm: React.FC<AuthFormProps> = ({ onDismiss, onPropsSave, prog
isDisabled={isDisabled}
isRequired
type="text"
id="rule-matchexpr"
aria-describedby="rule-matchexpr-helper"
id="matchexpr"
aria-describedby="matchexpr-helper"
onChange={(_event, v) => {
setMatchExpressionInput(v);
matchExprService.setSearchExpression(v);
Expand All @@ -268,12 +264,12 @@ export const AuthForm: React.FC<AuthFormProps> = ({ onDismiss, onPropsSave, prog
<HelperText>
<HelperTextItem variant={matchExpressionValid}>
{evaluating
? 'Evaluating Match Expression...'
? t('CreateCredentialModal.EVALUATING_EXPRESSION')
: matchExpressionValid === ValidatedOptions.warning
? `Warning: Match Expression matches no targets.`
? t('CreateCredentialModal.WARNING_NO_MATCH')
: matchExpressionValid === ValidatedOptions.error
? 'The expression matching failed.'
: `Enter a Match Expression. This is a Java-like code snippet that is evaluated against each target application to determine whether the rule should be applied.`}
? t('CreateCredentialModal.FAILING_EVALUATION')
: t('CreateCredentialModal.MATCH_EXPRESSION_HELPER_TEXT')}
</HelperTextItem>
</HelperText>
</FormHelperText>
Expand All @@ -285,6 +281,7 @@ export const AuthForm: React.FC<AuthFormProps> = ({ onDismiss, onPropsSave, prog
type _SupportedTab = 'visualizer' | 'test';

export const FormHelper: React.FC = ({ ...props }) => {
const { t } = useTranslation();
const alertOptions = React.useMemo(() => ({ hideActions: true }), []);
const [activeTab, setActiveTab] = React.useState<_SupportedTab>('visualizer');

Expand All @@ -302,7 +299,7 @@ export const FormHelper: React.FC = ({ ...props }) => {
<TabTitleIcon>
<TopologyIcon />
</TabTitleIcon>
<TabTitleText>Visualizer</TabTitleText>
<TabTitleText>{t('CreateCredentialModal.VISUALIZER')}</TabTitleText>
</>
}
>
Expand All @@ -317,7 +314,7 @@ export const FormHelper: React.FC = ({ ...props }) => {
<TabTitleIcon>
<FlaskIcon />
</TabTitleIcon>
<TabTitleText>Test</TabTitleText>
<TabTitleText>{t('TEST', { ns: 'common' })}</TabTitleText>
</>
}
>
Expand Down
Loading

0 comments on commit ad5a975

Please sign in to comment.