Merge pull request #4913 from jakemcdermott/list-item-date-formatting

Add basic date formatter

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot]
2019-10-07 14:27:39 +00:00
committed by GitHub
12 changed files with 111 additions and 42 deletions

View File

@@ -3,23 +3,16 @@ import { I18nProvider } from '@lingui/react';
import { HashRouter } from 'react-router-dom';
import { getLanguageWithoutRegionCode } from '@util/language';
import ja from '../build/locales/ja/messages';
import en from '../build/locales/en/messages';
export function getLanguage(nav) {
const language =
(nav.languages && nav.languages[0]) || nav.language || nav.userLanguage;
const languageWithoutRegionCode = language.toLowerCase().split(/[_-]+/)[0];
return languageWithoutRegionCode;
}
class RootProvider extends Component {
render() {
const { children } = this.props;
const catalogs = { en, ja };
const language = getLanguage(navigator);
const language = getLanguageWithoutRegionCode(navigator);
return (
<HashRouter>

View File

@@ -1,18 +0,0 @@
import { getLanguage } from './RootProvider';
describe('RootProvider.jsx', () => {
test('getLanguage returns the expected language code', () => {
expect(getLanguage({ languages: ['es-US'] })).toEqual('es');
expect(
getLanguage({
languages: ['es-US'],
language: 'fr-FR',
userLanguage: 'en-US',
})
).toEqual('es');
expect(getLanguage({ language: 'fr-FR', userLanguage: 'en-US' })).toEqual(
'fr'
);
expect(getLanguage({ userLanguage: 'en-US' })).toEqual('en');
});
});

View File

@@ -13,7 +13,8 @@ import ErrorDetail from '@components/ErrorDetail';
import LaunchButton from '@components/LaunchButton';
import { StatusIcon } from '@components/Sparkline';
import { toTitleCase } from '@util/strings';
import { Job } from '../../../types';
import { formatDateString } from '@util/dates';
import { Job } from '@types';
import {
JobsAPI,
ProjectUpdatesAPI,
@@ -140,8 +141,14 @@ function JobDetail({ job, i18n, history }) {
</StatusDetailValue>
}
/>
<Detail label={i18n._(t`Started`)} value={job.started} />
<Detail label={i18n._(t`Finished`)} value={job.finished} />
<Detail
label={i18n._(t`Started`)}
value={formatDateString(job.started)}
/>
<Detail
label={i18n._(t`Finished`)}
value={formatDateString(job.finished)}
/>
{jobTemplate && (
<Detail
label={i18n._(t`Template`)}

View File

@@ -29,8 +29,8 @@ describe('<JobDetail />', () => {
}
assertDetail('Status', 'Successful');
assertDetail('Started', mockJobData.started);
assertDetail('Finished', mockJobData.finished);
assertDetail('Started', '8/8/2019, 7:24:18 PM');
assertDetail('Finished', '8/8/2019, 7:24:50 PM');
assertDetail('Template', mockJobData.summary_fields.job_template.name);
assertDetail('Job Type', 'Run');
assertDetail('Launched By', mockJobData.summary_fields.created_by.username);

View File

@@ -15,6 +15,7 @@ import LaunchButton from '@components/LaunchButton';
import ListActionButton from '@components/ListActionButton';
import VerticalSeparator from '@components/VerticalSeparator';
import { toTitleCase } from '@util/strings';
import { formatDateString } from '@util/dates';
import { JOB_TYPE_URL_SEGMENTS } from '../../../constants';
class JobListItem extends Component {
@@ -46,7 +47,9 @@ class JobListItem extends Component {
</span>
</DataListCell>,
<DataListCell key="type">{toTitleCase(job.type)}</DataListCell>,
<DataListCell key="finished">{job.finished}</DataListCell>,
<DataListCell key="finished">
{formatDateString(job.finished)}
</DataListCell>,
<DataListCell lastcolumn="true" key="relaunch">
{job.type !== 'system_job' &&
job.summary_fields.user_capabilities.start && (

View File

@@ -10,6 +10,7 @@ import { DetailList, Detail } from '@components/DetailList';
import { ChipGroup, Chip } from '@components/Chip';
import ContentError from '@components/ContentError';
import ContentLoading from '@components/ContentLoading';
import { formatDateString } from '@util/dates';
const CardBody = styled(PFCardBody)`
padding-top: 20px;
@@ -53,7 +54,6 @@ class OrganizationDetail extends Component {
render() {
const { hasContentLoading, contentError, instanceGroups } = this.state;
const {
organization: {
name,
@@ -86,8 +86,14 @@ class OrganizationDetail extends Component {
label={i18n._(t`Ansible Environment`)}
value={custom_virtualenv}
/>
<Detail label={i18n._(t`Created`)} value={created} />
<Detail label={i18n._(t`Last Modified`)} value={modified} />
<Detail
label={i18n._(t`Created`)}
value={formatDateString(created)}
/>
<Detail
label={i18n._(t`Last Modified`)}
value={formatDateString(modified)}
/>
{instanceGroups && instanceGroups.length > 0 && (
<Detail
fullWidth

View File

@@ -13,8 +13,8 @@ describe('<OrganizationDetail />', () => {
description: 'Bar',
custom_virtualenv: 'Fizz',
max_hosts: '0',
created: 'Bat',
modified: 'Boo',
created: '2015-07-07T17:21:26.429745Z',
modified: '2019-08-11T19:47:37.980466Z',
summary_fields: {
user_capabilities: {
edit: true,
@@ -63,8 +63,8 @@ describe('<OrganizationDetail />', () => {
{ label: 'Name', value: 'Foo' },
{ label: 'Description', value: 'Bar' },
{ label: 'Ansible Environment', value: 'Fizz' },
{ label: 'Created', value: 'Bat' },
{ label: 'Last Modified', value: 'Boo' },
{ label: 'Created', value: '7/7/2015, 5:21:26 PM' },
{ label: 'Last Modified', value: '8/11/2019, 7:47:37 PM' },
{ label: 'Max Hosts', value: '0' },
];
// eslint-disable-next-line no-restricted-syntax

View File

@@ -17,6 +17,7 @@ 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 { JobTemplatesAPI } from '@api';
const ButtonGroup = styled.div`
@@ -168,11 +169,15 @@ class JobTemplateDetail extends Component {
<Detail label={i18n._(t`Timeout`)} value={timeout || '0'} />
<Detail
label={i18n._(t`Created`)}
value={`${created} by ${summary_fields.created_by.username}`} // TODO: link to user in users
value={`${formatDateString(created)} by ${
summary_fields.created_by.username
}`} // TODO: link to user in users
/>
<Detail
label={i18n._(t`Last Modified`)}
value={`${modified} by ${summary_fields.modified_by.username}`} // TODO: link to user in users
value={`${formatDateString(modified)} by ${
summary_fields.modified_by.username
}`} // TODO: link to user in users
/>
<Detail
label={i18n._(t`Show Changes`)}

View File

@@ -0,0 +1,6 @@
/* eslint-disable import/prefer-default-export */
import { getLanguage } from './language';
export function formatDateString(dateString, lang = getLanguage(navigator)) {
return new Date(dateString).toLocaleString(lang);
}

View File

@@ -0,0 +1,13 @@
import { formatDateString } from './dates';
describe('formatDateString', () => {
test('it returns the expected value', () => {
const lang = 'en-US';
expect(formatDateString('', lang)).toEqual('Invalid Date');
expect(formatDateString({}, lang)).toEqual('Invalid Date');
expect(formatDateString(undefined, lang)).toEqual('Invalid Date');
expect(formatDateString('2018-01-31T01:14:52.969227Z', lang)).toEqual(
'1/31/2018, 1:14:52 AM'
);
});
});

View File

@@ -0,0 +1,15 @@
export function getLanguage(nav) {
if (nav.languages && nav.languages[0]) {
return nav.languages[0];
}
if (nav.language) {
return nav.language;
}
return nav.userLanguage;
}
export function getLanguageWithoutRegionCode(nav) {
return getLanguage(nav)
.toLowerCase()
.split(/[_-]+/)[0];
}

View File

@@ -0,0 +1,39 @@
import { getLanguage, getLanguageWithoutRegionCode } from './language';
describe('getLanguage', () => {
test('it returns the expected language code', () => {
expect(getLanguage({ languages: ['es-US'] })).toEqual('es-US');
expect(
getLanguage({
languages: ['es-US'],
language: 'fr-FR',
userLanguage: 'en-US',
})
).toEqual('es-US');
expect(getLanguage({ language: 'fr-FR', userLanguage: 'en-US' })).toEqual(
'fr-FR'
);
expect(getLanguage({ userLanguage: 'en-US' })).toEqual('en-US');
});
});
describe('getLanguageWithoutRegionCode', () => {
test('it returns the expected (truncated) language code', () => {
expect(getLanguageWithoutRegionCode({ languages: ['es-US'] })).toEqual(
'es'
);
expect(
getLanguageWithoutRegionCode({
languages: ['es-US'],
language: 'fr-FR',
userLanguage: 'en-US',
})
).toEqual('es');
expect(
getLanguageWithoutRegionCode({ language: 'fr-FR', userLanguage: 'en-US' })
).toEqual('fr');
expect(getLanguageWithoutRegionCode({ userLanguage: 'en-US' })).toEqual(
'en'
);
});
});