mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 10:00:01 -03:30
Fix UserDateDetail translation
Add UserDateDetail to Org detail & InventoryGroupDetail Add VariablesDetail to InventoryGroupDetail
This commit is contained in:
parent
3d510c5064
commit
8ff0902177
@ -112,7 +112,7 @@ afterEach(() => {
|
||||
...
|
||||
```
|
||||
|
||||
**Test Attributes** -
|
||||
**Test Attributes** -
|
||||
It should be noted that the `dataCy` prop, as well as its equivalent attribute `data-cy`, are used as flags for any UI test that wants to avoid relying on brittle CSS selectors such as `nth-of-type()`.
|
||||
|
||||
## Handling API Errors
|
||||
@ -296,7 +296,7 @@ The lingui library provides various React helpers for dealing with both marking
|
||||
|
||||
**Note:** Variables that are put inside the t-marked template tag will not be translated. If you have a variable string with text that needs translating, you must wrap it in ```i18n._(t``)``` where it is defined.
|
||||
|
||||
**Note:** We do not use the `I18n` consumer, `i18nMark` function, or `<Trans>` component lingui gives us access to in this repo. i18nMark does not actually replace the string in the UI (leading to the potential for untranslated bugs), and the other helpers are redundant. Settling on a consistent, single pattern helps us ease the mental overhead of the need to understand the ins and outs of the lingui API.
|
||||
**Note:** We try to avoid the `I18n` consumer, `i18nMark` function, or `<Trans>` component lingui gives us access to in this repo. i18nMark does not actually replace the string in the UI (leading to the potential for untranslated bugs), and the other helpers are redundant. Settling on a consistent, single pattern helps us ease the mental overhead of the need to understand the ins and outs of the lingui API.
|
||||
|
||||
You can learn more about the ways lingui and its React helpers at [this link](https://lingui.js.org/tutorials/react-patterns.html).
|
||||
|
||||
|
||||
@ -14,6 +14,10 @@ function VariablesDetail({ value, label, rows }) {
|
||||
const [currentValue, setCurrentValue] = useState(value);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<DetailName
|
||||
|
||||
@ -1,20 +1,25 @@
|
||||
import React from 'react';
|
||||
import { node, string } from 'prop-types';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { formatDateString } from '@util/dates';
|
||||
import Detail from './Detail';
|
||||
import { SummaryFieldUser } from '../../types';
|
||||
|
||||
function UserDateDetail({ label, date, user }) {
|
||||
const dateStr = formatDateString(date);
|
||||
const username = user ? user.username : '';
|
||||
return (
|
||||
<Detail
|
||||
label={label}
|
||||
value={
|
||||
<span>
|
||||
{formatDateString(date)}
|
||||
{user && ' by '}
|
||||
{user && <Link to={`/users/${user.id}`}>{user.username}</Link>}
|
||||
</span>
|
||||
user ? (
|
||||
<Trans>
|
||||
{dateStr} by <Link to={`/users/${user.id}`}>{username}</Link>
|
||||
</Trans>
|
||||
) : (
|
||||
dateStr
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -68,13 +68,11 @@ function InventoryDetail({ inventory, i18n }) {
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
{inventory.variables && (
|
||||
<VariablesDetail
|
||||
label={i18n._(t`Variables`)}
|
||||
value={inventory.variables}
|
||||
rows={4}
|
||||
/>
|
||||
)}
|
||||
<VariablesDetail
|
||||
label={i18n._(t`Variables`)}
|
||||
value={inventory.variables}
|
||||
rows={4}
|
||||
/>
|
||||
<UserDateDetail
|
||||
label={i18n._(t`Created`)}
|
||||
date={inventory.created}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { CardHeader } from '@patternfly/react-core';
|
||||
|
||||
import { Switch, Route, withRouter, Link, Redirect } from 'react-router-dom';
|
||||
import { GroupsAPI } from '@api';
|
||||
@ -9,6 +8,7 @@ import CardCloseButton from '@components/CardCloseButton';
|
||||
import RoutedTabs from '@components/RoutedTabs';
|
||||
import ContentError from '@components/ContentError';
|
||||
import ContentLoading from '@components/ContentLoading';
|
||||
import { TabbedCardHeader } from '@components/Card';
|
||||
import InventoryGroupEdit from '../InventoryGroupEdit/InventoryGroupEdit';
|
||||
import InventoryGroupDetail from '../InventoryGroupDetail/InventoryGroupDetail';
|
||||
|
||||
@ -97,12 +97,12 @@ function InventoryGroups({ i18n, match, setBreadcrumb, inventory, history }) {
|
||||
!history.location.pathname.endsWith('edit')
|
||||
) {
|
||||
cardHeader = (
|
||||
<CardHeader style={{ padding: 0 }}>
|
||||
<TabbedCardHeader>
|
||||
<RoutedTabs history={history} tabsArray={tabsArray} />
|
||||
<CardCloseButton
|
||||
linkTo={`/inventories/inventory/${inventory.id}/groups`}
|
||||
/>
|
||||
</CardHeader>
|
||||
</TabbedCardHeader>
|
||||
);
|
||||
}
|
||||
return (
|
||||
|
||||
@ -3,23 +3,16 @@ import { t } from '@lingui/macro';
|
||||
|
||||
import { CardBody, Button } from '@patternfly/react-core';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { withRouter, Link } from 'react-router-dom';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
import { VariablesInput as CodeMirrorInput } from '@components/CodeMirrorInput';
|
||||
import { VariablesDetail } from '@components/CodeMirrorInput';
|
||||
import ErrorDetail from '@components/ErrorDetail';
|
||||
import AlertModal from '@components/AlertModal';
|
||||
import { formatDateString } from '@util/dates';
|
||||
|
||||
import { GroupsAPI } from '@api';
|
||||
import { DetailList, Detail } from '@components/DetailList';
|
||||
import { DetailList, Detail, UserDateDetail } from '@components/DetailList';
|
||||
|
||||
const VariablesInput = styled(CodeMirrorInput)`
|
||||
.pf-c-form__label {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
margin: 20px 0;
|
||||
`;
|
||||
// TODO: extract this into a component for use in all relevant Detail views
|
||||
const ActionButtonWrapper = styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
@ -28,6 +21,7 @@ const ActionButtonWrapper = styled.div`
|
||||
margin-left: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
function InventoryGroupDetail({ i18n, history, match, inventoryGroup }) {
|
||||
const {
|
||||
summary_fields: { created_by, modified_by },
|
||||
@ -50,52 +44,26 @@ function InventoryGroupDetail({ i18n, history, match, inventoryGroup }) {
|
||||
}
|
||||
};
|
||||
|
||||
let createdBy = '';
|
||||
if (created) {
|
||||
if (created_by && created_by.username) {
|
||||
createdBy = (
|
||||
<span>
|
||||
{i18n._(t`${formatDateString(inventoryGroup.created)} by`)}{' '}
|
||||
<Link to={`/users/${created_by.id}`}>{created_by.username}</Link>
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
createdBy = formatDateString(inventoryGroup.created);
|
||||
}
|
||||
}
|
||||
|
||||
let modifiedBy = '';
|
||||
if (modified) {
|
||||
if (modified_by && modified_by.username) {
|
||||
modifiedBy = (
|
||||
<span>
|
||||
{i18n._(t`${formatDateString(inventoryGroup.modified)} by`)}{' '}
|
||||
<Link to={`/users/${modified_by.id}`}>{modified_by.username}</Link>
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
modifiedBy = formatDateString(inventoryGroup.modified);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<CardBody css="padding-top: 20px">
|
||||
<CardBody>
|
||||
<DetailList gutter="sm">
|
||||
<Detail label={i18n._(t`Name`)} value={name} />
|
||||
<Detail label={i18n._(t`Description`)} value={description} />
|
||||
</DetailList>
|
||||
<VariablesInput
|
||||
id="inventoryGroup-variables"
|
||||
readOnly
|
||||
value={variables}
|
||||
rows={4}
|
||||
label={i18n._(t`Variables`)}
|
||||
/>
|
||||
<DetailList>
|
||||
{createdBy && <Detail label={i18n._(t`Created`)} value={createdBy} />}
|
||||
{modifiedBy && (
|
||||
<Detail label={i18n._(t`Modified`)} value={modifiedBy} />
|
||||
)}
|
||||
<VariablesDetail
|
||||
label={i18n._(t`Variables`)}
|
||||
value={variables}
|
||||
rows={4}
|
||||
/>
|
||||
<UserDateDetail
|
||||
label={i18n._(t`Created`)}
|
||||
date={created}
|
||||
user={created_by}
|
||||
/>
|
||||
<UserDateDetail
|
||||
label={i18n._(t`Last Modified`)}
|
||||
date={modified}
|
||||
user={modified_by}
|
||||
/>
|
||||
</DetailList>
|
||||
<ActionButtonWrapper>
|
||||
<Button
|
||||
|
||||
@ -4,10 +4,9 @@ import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import styled from 'styled-components';
|
||||
import { Project } from '@types';
|
||||
import { formatDateString } from '@util/dates';
|
||||
import { Config } from '@contexts/Config';
|
||||
import { Button, CardBody, List, ListItem } from '@patternfly/react-core';
|
||||
import { DetailList, Detail } from '@components/DetailList';
|
||||
import { DetailList, Detail, UserDateDetail } from '@components/DetailList';
|
||||
import { CredentialChip } from '@components/Chip';
|
||||
import { toTitleCase } from '@util/strings';
|
||||
|
||||
@ -64,30 +63,6 @@ function ProjectDetail({ project, i18n }) {
|
||||
);
|
||||
}
|
||||
|
||||
let createdBy = '';
|
||||
if (created) {
|
||||
if (summary_fields.created_by && summary_fields.created_by.username) {
|
||||
createdBy = i18n._(
|
||||
t`${formatDateString(created)} by ${summary_fields.created_by.username}`
|
||||
);
|
||||
} else {
|
||||
createdBy = formatDateString(created);
|
||||
}
|
||||
}
|
||||
|
||||
let modifiedBy = '';
|
||||
if (modified) {
|
||||
if (summary_fields.modified_by && summary_fields.modified_by.username) {
|
||||
modifiedBy = i18n._(
|
||||
t`${formatDateString(modified)} by ${
|
||||
summary_fields.modified_by.username
|
||||
}`
|
||||
);
|
||||
} else {
|
||||
modifiedBy = formatDateString(modified);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<CardBody>
|
||||
<DetailList gutter="sm">
|
||||
@ -150,10 +125,16 @@ function ProjectDetail({ project, i18n }) {
|
||||
)}
|
||||
</Config>
|
||||
<Detail label={i18n._(t`Playbook Directory`)} value={local_path} />
|
||||
{/* TODO: Link to user in users */}
|
||||
<Detail label={i18n._(t`Created`)} value={createdBy} />
|
||||
{/* TODO: Link to user in users */}
|
||||
<Detail label={i18n._(t`Last Modified`)} value={modifiedBy} />
|
||||
<UserDateDetail
|
||||
label={i18n._(t`Created`)}
|
||||
date={created}
|
||||
user={summary_fields.created_by}
|
||||
/>
|
||||
<UserDateDetail
|
||||
label={i18n._(t`Last Modified`)}
|
||||
date={modified}
|
||||
user={summary_fields.modified_by}
|
||||
/>
|
||||
</DetailList>
|
||||
<ActionButtonWrapper>
|
||||
{summary_fields.user_capabilities &&
|
||||
|
||||
@ -16,8 +16,7 @@ import ContentError from '@components/ContentError';
|
||||
import LaunchButton from '@components/LaunchButton';
|
||||
import ContentLoading from '@components/ContentLoading';
|
||||
import { ChipGroup, Chip, CredentialChip } from '@components/Chip';
|
||||
import { DetailList, Detail } from '@components/DetailList';
|
||||
import { formatDateString } from '@util/dates';
|
||||
import { DetailList, Detail, UserDateDetail } from '@components/DetailList';
|
||||
import { JobTemplatesAPI } from '@api';
|
||||
|
||||
const ButtonGroup = styled.div`
|
||||
@ -112,32 +111,6 @@ class JobTemplateDetail extends Component {
|
||||
const renderOptionsField =
|
||||
become_enabled || host_config_key || allow_simultaneous || use_fact_cache;
|
||||
|
||||
let createdBy = '';
|
||||
if (created) {
|
||||
if (summary_fields.created_by && summary_fields.created_by.username) {
|
||||
createdBy = i18n._(
|
||||
t`${formatDateString(created)} by ${
|
||||
summary_fields.created_by.username
|
||||
}`
|
||||
);
|
||||
} else {
|
||||
createdBy = formatDateString(created);
|
||||
}
|
||||
}
|
||||
|
||||
let modifiedBy = '';
|
||||
if (modified) {
|
||||
if (summary_fields.modified_by && summary_fields.modified_by.username) {
|
||||
modifiedBy = i18n._(
|
||||
t`${formatDateString(modified)} by ${
|
||||
summary_fields.modified_by.username
|
||||
}`
|
||||
);
|
||||
} else {
|
||||
modifiedBy = formatDateString(modified);
|
||||
}
|
||||
}
|
||||
|
||||
const renderOptions = (
|
||||
<TextList component={TextListVariants.ul}>
|
||||
{become_enabled && (
|
||||
@ -239,18 +212,16 @@ class JobTemplateDetail extends Component {
|
||||
value={verbosityDetails[0].details}
|
||||
/>
|
||||
<Detail label={i18n._(t`Timeout`)} value={timeout || '0'} />
|
||||
{createdBy && (
|
||||
<Detail
|
||||
label={i18n._(t`Created`)}
|
||||
value={createdBy} // TODO: link to user in users
|
||||
/>
|
||||
)}
|
||||
{modifiedBy && (
|
||||
<Detail
|
||||
label={i18n._(t`Last Modified`)}
|
||||
value={modifiedBy} // TODO: link to user in users
|
||||
/>
|
||||
)}
|
||||
<UserDateDetail
|
||||
label={i18n._(t`Created`)}
|
||||
date={created}
|
||||
user={summary_fields.created_by}
|
||||
/>
|
||||
<UserDateDetail
|
||||
label={i18n._(t`Last Modified`)}
|
||||
date={modified}
|
||||
user={summary_fields.modified_by}
|
||||
/>
|
||||
<Detail
|
||||
label={i18n._(t`Show Changes`)}
|
||||
value={diff_mode ? 'On' : 'Off'}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user