mirror of
https://github.com/strapi/strapi.git
synced 2025-09-26 00:39:49 +00:00
Add info box
Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
parent
2bbe7175c4
commit
f12bda0e7b
@ -0,0 +1,63 @@
|
|||||||
|
import React, { useRef } from 'react';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
import { useContentManagerEditViewDataManager } from '@strapi/helper-plugin';
|
||||||
|
import { Box } from '@strapi/parts/Box';
|
||||||
|
import { Divider } from '@strapi/parts/Divider';
|
||||||
|
import { Text } from '@strapi/parts/Text';
|
||||||
|
import { Row } from '@strapi/parts/Row';
|
||||||
|
import { Stack } from '@strapi/parts/Stack';
|
||||||
|
import { getTrad } from '../../../utils';
|
||||||
|
import getUnits from './utils/getUnits';
|
||||||
|
|
||||||
|
const Informations = () => {
|
||||||
|
const { formatMessage, formatRelativeTime } = useIntl();
|
||||||
|
const { initialData, isCreatingEntry } = useContentManagerEditViewDataManager();
|
||||||
|
|
||||||
|
// TODO if timestamps are still configurable in the V4
|
||||||
|
const updatedAt = 'updated_at';
|
||||||
|
const updatedByFirstname = initialData.updated_by?.firstname || '';
|
||||||
|
const updatedByLastname = initialData.updated_by?.lastname || '';
|
||||||
|
const updatedByUsername = initialData.updated_by?.username;
|
||||||
|
const updatedBy = updatedByUsername || `${updatedByFirstname} ${updatedByLastname}`;
|
||||||
|
const currentTime = useRef(new Date().getTime());
|
||||||
|
const timestamp = initialData[updatedAt]
|
||||||
|
? new Date(initialData[updatedAt]).getTime()
|
||||||
|
: Date.now();
|
||||||
|
const elapsed = timestamp - currentTime.current;
|
||||||
|
|
||||||
|
const { unit, value } = getUnits(-elapsed);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Text textColor="neutral600" bold small style={{ textTransform: 'uppercase' }}>
|
||||||
|
{formatMessage({
|
||||||
|
id: getTrad('containers.Edit.information'),
|
||||||
|
defaultMessage: 'Information',
|
||||||
|
})}
|
||||||
|
</Text>
|
||||||
|
<Box paddingTop={2} paddingBottom={6}>
|
||||||
|
<Divider />
|
||||||
|
</Box>
|
||||||
|
<Stack size={4}>
|
||||||
|
<Row justifyContent="space-between">
|
||||||
|
<Text bold>
|
||||||
|
{formatMessage({
|
||||||
|
id: getTrad('containers.Edit.information.lastUpdate'),
|
||||||
|
})}
|
||||||
|
</Text>
|
||||||
|
<Text>{formatRelativeTime(value, unit, { numeric: 'auto' })}</Text>
|
||||||
|
</Row>
|
||||||
|
<Row justifyContent="space-between">
|
||||||
|
<Text bold>
|
||||||
|
{formatMessage({
|
||||||
|
id: getTrad('containers.Edit.information.by'),
|
||||||
|
})}
|
||||||
|
</Text>
|
||||||
|
<Text>{isCreatingEntry ? '-' : updatedBy}</Text>
|
||||||
|
</Row>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Informations;
|
@ -0,0 +1,178 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* Tests for Informations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { IntlProvider } from 'react-intl';
|
||||||
|
import { useContentManagerEditViewDataManager } from '@strapi/helper-plugin';
|
||||||
|
import Theme from '../../../../../components/Theme';
|
||||||
|
import Informations from '../index';
|
||||||
|
|
||||||
|
jest.mock('@strapi/helper-plugin', () => ({
|
||||||
|
useContentManagerEditViewDataManager: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const makeApp = () => {
|
||||||
|
return (
|
||||||
|
<IntlProvider
|
||||||
|
locale="en"
|
||||||
|
defaultLocale="en"
|
||||||
|
messages={{ 'containers.Edit.information': 'Information' }}
|
||||||
|
>
|
||||||
|
<Theme>
|
||||||
|
<Informations />
|
||||||
|
</Theme>
|
||||||
|
</IntlProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('CONTENT MANAGER | EditView | Header', () => {
|
||||||
|
const RealNow = Date.now;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
global.Date.now = jest.fn(() => new Date('2021-09-20').getTime());
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
global.Date.now = RealNow;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders and matches the snaphsot', () => {
|
||||||
|
useContentManagerEditViewDataManager.mockImplementationOnce(() => ({
|
||||||
|
initialData: {},
|
||||||
|
isCreatingEntry: true,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const {
|
||||||
|
container: { firstChild },
|
||||||
|
} = render(makeApp());
|
||||||
|
|
||||||
|
expect(firstChild).toMatchInlineSnapshot(`
|
||||||
|
.c1 {
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c2 {
|
||||||
|
background: #eaeaef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3 {
|
||||||
|
height: 1px;
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c0 {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.33;
|
||||||
|
color: #666687;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c6 {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.43;
|
||||||
|
color: #32324d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c7 {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.43;
|
||||||
|
color: #32324d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c5 {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-flex-direction: row;
|
||||||
|
-ms-flex-direction: row;
|
||||||
|
flex-direction: row;
|
||||||
|
-webkit-box-pack: justify;
|
||||||
|
-webkit-justify-content: space-between;
|
||||||
|
-ms-flex-pack: justify;
|
||||||
|
justify-content: space-between;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c4 {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-flex-direction: column;
|
||||||
|
-ms-flex-direction: column;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c4 > * {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c4 > * + * {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
<div
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="c0"
|
||||||
|
style="text-transform: uppercase;"
|
||||||
|
>
|
||||||
|
Information
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="c1"
|
||||||
|
>
|
||||||
|
<hr
|
||||||
|
class="c2 c3"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="c4"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="c5"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="c6"
|
||||||
|
>
|
||||||
|
content-manager.containers.Edit.information.lastUpdate
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="c7"
|
||||||
|
>
|
||||||
|
7 hours ago
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="c5"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="c6"
|
||||||
|
>
|
||||||
|
content-manager.containers.Edit.information.by
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="c7"
|
||||||
|
>
|
||||||
|
-
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,27 @@
|
|||||||
|
const msPerMinute = 60 * 1000;
|
||||||
|
const msPerHour = msPerMinute * 60;
|
||||||
|
const msPerDay = msPerHour * 24;
|
||||||
|
const msPerMonth = msPerDay * 30;
|
||||||
|
const msPerYear = msPerDay * 365;
|
||||||
|
|
||||||
|
const getUnits = value => {
|
||||||
|
if (value < msPerMinute) {
|
||||||
|
return { unit: 'second', value: -Math.round(value / 1000) };
|
||||||
|
}
|
||||||
|
if (value < msPerHour) {
|
||||||
|
return { unit: 'minute', value: -Math.round(value / msPerMinute) };
|
||||||
|
}
|
||||||
|
if (value < msPerDay) {
|
||||||
|
return { unit: 'hour', value: -Math.round(value / msPerHour) };
|
||||||
|
}
|
||||||
|
if (value < msPerMonth) {
|
||||||
|
return { unit: 'day', value: -Math.round(value / msPerDay) };
|
||||||
|
}
|
||||||
|
if (value < msPerYear) {
|
||||||
|
return { unit: 'month', value: -Math.round(value / msPerMonth) };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { unit: 'year', value: -Math.round(value / msPerYear) };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getUnits;
|
@ -29,6 +29,7 @@ import CollectionTypeFormWrapper from '../../components/CollectionTypeFormWrappe
|
|||||||
import EditViewDataManagerProvider from '../../components/EditViewDataManagerProvider';
|
import EditViewDataManagerProvider from '../../components/EditViewDataManagerProvider';
|
||||||
import SingleTypeFormWrapper from '../../components/SingleTypeFormWrapper';
|
import SingleTypeFormWrapper from '../../components/SingleTypeFormWrapper';
|
||||||
import DraftAndPublishBadge from './DraftAndPublishBadge';
|
import DraftAndPublishBadge from './DraftAndPublishBadge';
|
||||||
|
import Informations from './Informations';
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
import {
|
import {
|
||||||
// createAttributesLayout,
|
// createAttributesLayout,
|
||||||
@ -165,7 +166,7 @@ const EditView = ({
|
|||||||
paddingRight={4}
|
paddingRight={4}
|
||||||
paddingTop={6}
|
paddingTop={6}
|
||||||
>
|
>
|
||||||
infos + InjectionZone
|
<Informations />
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</GridItem>
|
</GridItem>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user