mirror of
https://github.com/strapi/strapi.git
synced 2025-11-10 15:19:00 +00:00
Display relations and medias
Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
parent
39abc06a21
commit
5a7dbe742a
@ -115,6 +115,30 @@
|
|||||||
"component": "blog.test-como",
|
"component": "blog.test-como",
|
||||||
"required": false,
|
"required": false,
|
||||||
"min": 2
|
"min": 2
|
||||||
|
},
|
||||||
|
"temp_one_to_one": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "oneToOne",
|
||||||
|
"target": "api::temp.temp",
|
||||||
|
"inversedBy": "one_to_one"
|
||||||
|
},
|
||||||
|
"temp": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "manyToOne",
|
||||||
|
"target": "api::temp.temp",
|
||||||
|
"inversedBy": "one_to_many"
|
||||||
|
},
|
||||||
|
"temps": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "oneToMany",
|
||||||
|
"target": "api::temp.temp",
|
||||||
|
"mappedBy": "many_to_one"
|
||||||
|
},
|
||||||
|
"many_to_many_temp": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "manyToMany",
|
||||||
|
"target": "api::temp.temp",
|
||||||
|
"inversedBy": "many_to_many"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,15 +5,26 @@
|
|||||||
"displayName": "Category",
|
"displayName": "Category",
|
||||||
"singularName": "category",
|
"singularName": "category",
|
||||||
"pluralName": "categories",
|
"pluralName": "categories",
|
||||||
"description": ""
|
"description": "",
|
||||||
|
"name": "Category"
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"draftAndPublish": true,
|
"draftAndPublish": true,
|
||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
|
"pluginOptions": {
|
||||||
|
"i18n": {
|
||||||
|
"localized": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"pluginOptions": {
|
||||||
|
"i18n": {
|
||||||
|
"localized": true
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"addresses": {
|
"addresses": {
|
||||||
"type": "relation",
|
"type": "relation",
|
||||||
|
|||||||
115
examples/getstarted/api/temp/content-types/temp/schema.json
Normal file
115
examples/getstarted/api/temp/content-types/temp/schema.json
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
{
|
||||||
|
"kind": "collectionType",
|
||||||
|
"collectionName": "temps",
|
||||||
|
"info": {
|
||||||
|
"singularName": "temp",
|
||||||
|
"pluralName": "temps",
|
||||||
|
"displayName": "temp",
|
||||||
|
"name": "temp",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"draftAndPublish": true
|
||||||
|
},
|
||||||
|
"pluginOptions": {},
|
||||||
|
"attributes": {
|
||||||
|
"short": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"long": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "email"
|
||||||
|
},
|
||||||
|
"rich": {
|
||||||
|
"type": "richtext"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "password"
|
||||||
|
},
|
||||||
|
"number": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"enum": {
|
||||||
|
"type": "enumeration",
|
||||||
|
"enum": [
|
||||||
|
"one",
|
||||||
|
"two",
|
||||||
|
"three"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"datetime": {
|
||||||
|
"type": "datetime"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"type": "time"
|
||||||
|
},
|
||||||
|
"single": {
|
||||||
|
"type": "media",
|
||||||
|
"multiple": false,
|
||||||
|
"required": false,
|
||||||
|
"allowedTypes": [
|
||||||
|
"images",
|
||||||
|
"files",
|
||||||
|
"videos"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"multiple": {
|
||||||
|
"type": "media",
|
||||||
|
"multiple": true,
|
||||||
|
"required": false,
|
||||||
|
"allowedTypes": [
|
||||||
|
"images",
|
||||||
|
"files",
|
||||||
|
"videos"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"bool": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
"uid": {
|
||||||
|
"type": "uid"
|
||||||
|
},
|
||||||
|
"one_way": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "oneToOne",
|
||||||
|
"target": "api::address.address"
|
||||||
|
},
|
||||||
|
"one_to_one": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "oneToOne",
|
||||||
|
"target": "api::address.address",
|
||||||
|
"inversedBy": "temp_one_to_one"
|
||||||
|
},
|
||||||
|
"one_to_many": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "oneToMany",
|
||||||
|
"target": "api::address.address",
|
||||||
|
"mappedBy": "temp"
|
||||||
|
},
|
||||||
|
"many_to_one": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "manyToOne",
|
||||||
|
"target": "api::address.address",
|
||||||
|
"inversedBy": "temps"
|
||||||
|
},
|
||||||
|
"many_to_many": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "manyToMany",
|
||||||
|
"target": "api::address.address",
|
||||||
|
"inversedBy": "many_to_many_temp"
|
||||||
|
},
|
||||||
|
"many_way": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "oneToMany",
|
||||||
|
"target": "api::address.address"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
examples/getstarted/api/temp/controllers/temp.js
Normal file
15
examples/getstarted/api/temp/controllers/temp.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of functions called "actions" for `temp`
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// exampleAction: async (ctx, next) => {
|
||||||
|
// try {
|
||||||
|
// ctx.body = 'ok';
|
||||||
|
// } catch (err) {
|
||||||
|
// ctx.body = err;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
};
|
||||||
44
examples/getstarted/api/temp/routes/temp.js
Normal file
44
examples/getstarted/api/temp/routes/temp.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
module.exports = {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
path: '/temps',
|
||||||
|
handler: 'temp.find',
|
||||||
|
config: {
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
path: '/temps/:id',
|
||||||
|
handler: 'temp.findOne',
|
||||||
|
config: {
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
path: '/temps',
|
||||||
|
handler: 'temp.create',
|
||||||
|
config: {
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'PUT',
|
||||||
|
path: '/temps/:id',
|
||||||
|
handler: 'temp.update',
|
||||||
|
config: {
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'DELETE',
|
||||||
|
path: '/temps/:id',
|
||||||
|
handler: 'temp.delete',
|
||||||
|
config: {
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Avatar } from '@strapi/parts/Avatar';
|
||||||
|
import { Text } from '@strapi/parts/Text';
|
||||||
|
import { getFileExtension, prefixFileUrlWithBackendUrl } from '@strapi/helper-plugin';
|
||||||
|
|
||||||
|
const Media = ({ url, mime, alternativeText, name, ext, formats }) => {
|
||||||
|
const fileURL = prefixFileUrlWithBackendUrl(url);
|
||||||
|
|
||||||
|
if (mime.includes('image')) {
|
||||||
|
const thumbnail = formats?.thumbnail?.url || null;
|
||||||
|
const mediaURL = prefixFileUrlWithBackendUrl(thumbnail) || fileURL;
|
||||||
|
|
||||||
|
return <Avatar src={mediaURL} alt={alternativeText || name} preview />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileExtension = getFileExtension(ext);
|
||||||
|
|
||||||
|
return <Text textColor="neutral800">{fileExtension}</Text>;
|
||||||
|
};
|
||||||
|
|
||||||
|
Media.defaultProps = {
|
||||||
|
alternativeText: null,
|
||||||
|
formats: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
Media.propTypes = {
|
||||||
|
alternativeText: PropTypes.string,
|
||||||
|
ext: PropTypes.string.isRequired,
|
||||||
|
formats: PropTypes.object,
|
||||||
|
mime: PropTypes.string.isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
url: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Media;
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Text } from '@strapi/parts/Text';
|
||||||
|
|
||||||
|
const MultipleMedia = () => {
|
||||||
|
return <Text textColor="neutral800">TODO</Text>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MultipleMedia;
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Box } from '@strapi/parts/Box';
|
||||||
|
import { Text } from '@strapi/parts/Text';
|
||||||
|
import { Loader } from '@strapi/parts/Loader';
|
||||||
|
import { useNotifyAT } from '@strapi/parts/LiveRegions';
|
||||||
|
import { axiosInstance } from '../../../../../core/utils';
|
||||||
|
import { getRequestUrl } from '../../../../utils';
|
||||||
|
import formatDisplayedValue from '../utils/formatDisplayedValue';
|
||||||
|
|
||||||
|
const fetchRelation = async (endPoint, notifyStatus) => {
|
||||||
|
const {
|
||||||
|
data: { results, pagination },
|
||||||
|
} = await axiosInstance.get(endPoint);
|
||||||
|
|
||||||
|
notifyStatus('The relations has been loaded');
|
||||||
|
|
||||||
|
return { results, pagination };
|
||||||
|
};
|
||||||
|
|
||||||
|
const PopoverContent = ({ fieldSchema, name, rowId, targetModel, queryInfos }) => {
|
||||||
|
const requestURL = getRequestUrl(`${queryInfos.endPoint}/${rowId}/${name}`);
|
||||||
|
|
||||||
|
const { formatDate, formatTime, formatNumber, formatMessage } = useIntl();
|
||||||
|
const { notifyStatus } = useNotifyAT();
|
||||||
|
|
||||||
|
const { data, status } = useQuery([targetModel, rowId], () =>
|
||||||
|
fetchRelation(requestURL, notifyStatus)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (status !== 'success') {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Loader>Loading content</Loader>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
{data?.results.map(entry => {
|
||||||
|
const displayedValue = entry[fieldSchema.name]
|
||||||
|
? formatDisplayedValue(entry[fieldSchema.name], fieldSchema.type, {
|
||||||
|
formatDate,
|
||||||
|
formatTime,
|
||||||
|
formatNumber,
|
||||||
|
formatMessage,
|
||||||
|
})
|
||||||
|
: '-';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box as="li" key={entry.id} padding={3}>
|
||||||
|
<Text>{displayedValue}</Text>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{data?.pagination.total > 10 && (
|
||||||
|
<Box as="li" padding={3}>
|
||||||
|
<Text>[...]</Text>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
PopoverContent.propTypes = {
|
||||||
|
fieldSchema: PropTypes.shape({ name: PropTypes.string, type: PropTypes.string }).isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
rowId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
|
targetModel: PropTypes.string.isRequired,
|
||||||
|
queryInfos: PropTypes.shape({
|
||||||
|
endPoint: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PopoverContent;
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
import React, { useState, useRef } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
import toString from 'lodash/toString';
|
||||||
|
import { IconButton } from '@strapi/parts/IconButton';
|
||||||
|
import { Text } from '@strapi/parts/Text';
|
||||||
|
import { Box } from '@strapi/parts/Box';
|
||||||
|
import { Badge } from '@strapi/parts/Badge';
|
||||||
|
import { Row } from '@strapi/parts/Row';
|
||||||
|
import { Popover } from '@strapi/parts/Popover';
|
||||||
|
import { SortIcon } from '@strapi/helper-plugin';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import formatDisplayedValue from '../utils/formatDisplayedValue';
|
||||||
|
import PopoverContent from './PopoverContent';
|
||||||
|
|
||||||
|
const SINGLE_RELATIONS = ['oneToOne', 'manyToOne'];
|
||||||
|
|
||||||
|
const ActionWrapper = styled.span`
|
||||||
|
svg {
|
||||||
|
height: ${4 / 16}rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const RelationCountBadge = styled(Badge)`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: ${20 / 16}rem;
|
||||||
|
width: ${16 / 16}rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Relation = ({ fieldSchema, metadatas, queryInfos, name, rowId, value }) => {
|
||||||
|
const { formatDate, formatTime, formatNumber, formatMessage } = useIntl();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const buttonRef = useRef();
|
||||||
|
|
||||||
|
if (SINGLE_RELATIONS.includes(fieldSchema.relation)) {
|
||||||
|
const formattedValue = formatDisplayedValue(
|
||||||
|
value[metadatas.mainField.name],
|
||||||
|
metadatas.mainField.schema.type,
|
||||||
|
{
|
||||||
|
formatDate,
|
||||||
|
formatTime,
|
||||||
|
formatNumber,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return <Text textColor="neutral800">{toString(formattedValue)}</Text>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTogglePopover = () => setVisible(prev => !prev);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row>
|
||||||
|
<RelationCountBadge>{value.count}</RelationCountBadge>
|
||||||
|
<Box paddingLeft={2}>
|
||||||
|
<Text textColor="neutral800">
|
||||||
|
{formatMessage(
|
||||||
|
{
|
||||||
|
id: 'content-manager.containers.ListPage.items',
|
||||||
|
defaultMessage: '{number, plural, =0 {items} one {item} other {items}}',
|
||||||
|
},
|
||||||
|
{ number: value.count }
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
{value.count > 0 && (
|
||||||
|
<ActionWrapper>
|
||||||
|
<IconButton
|
||||||
|
onClick={handleTogglePopover}
|
||||||
|
ref={buttonRef}
|
||||||
|
noBorder
|
||||||
|
label={formatMessage({
|
||||||
|
id: 'content-manager.popover.display-relations.label',
|
||||||
|
defaultMessage: 'Display relations',
|
||||||
|
})}
|
||||||
|
icon={<SortIcon isUp={visible} />}
|
||||||
|
/>
|
||||||
|
{visible && (
|
||||||
|
<Popover source={buttonRef} spacingTop={4} centered>
|
||||||
|
<PopoverContent
|
||||||
|
queryInfos={queryInfos}
|
||||||
|
name={name}
|
||||||
|
fieldSchema={metadatas.mainField}
|
||||||
|
targetModel={fieldSchema.targetModel}
|
||||||
|
rowId={rowId}
|
||||||
|
count={value.count}
|
||||||
|
/>
|
||||||
|
</Popover>
|
||||||
|
)}
|
||||||
|
</ActionWrapper>
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Relation.propTypes = {
|
||||||
|
fieldSchema: PropTypes.shape({
|
||||||
|
relation: PropTypes.string,
|
||||||
|
targetModel: PropTypes.string,
|
||||||
|
type: PropTypes.string.isRequired,
|
||||||
|
}).isRequired,
|
||||||
|
metadatas: PropTypes.shape({
|
||||||
|
mainField: PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
schema: PropTypes.shape({ type: PropTypes.string.isRequired }).isRequired,
|
||||||
|
}),
|
||||||
|
}).isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
rowId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
|
queryInfos: PropTypes.shape({ endPoint: PropTypes.string.isRequired }).isRequired,
|
||||||
|
value: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Relation;
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Text } from '@strapi/parts/Text';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
import toString from 'lodash/toString';
|
||||||
|
import formatDisplayedValue from './utils/formatDisplayedValue';
|
||||||
|
import Media from './Media';
|
||||||
|
import MultipleMedias from './MultipleMedias';
|
||||||
|
import Relation from './Relation';
|
||||||
|
|
||||||
|
const CellContent = ({ content, fieldSchema, metadatas, name, queryInfos, rowId }) => {
|
||||||
|
const { formatDate, formatTime, formatNumber } = useIntl();
|
||||||
|
|
||||||
|
if (content === null || content === undefined) {
|
||||||
|
return <Text textColor="neutral800">-</Text>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let formattedContent = formatDisplayedValue(content, fieldSchema.type, {
|
||||||
|
formatDate,
|
||||||
|
formatTime,
|
||||||
|
formatNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fieldSchema.type === 'media' && !fieldSchema.multiple) {
|
||||||
|
return <Media {...content} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldSchema.type === 'media' && fieldSchema.multiple) {
|
||||||
|
return <MultipleMedias {...content} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldSchema.type === 'relation') {
|
||||||
|
return (
|
||||||
|
<Relation
|
||||||
|
fieldSchema={fieldSchema}
|
||||||
|
queryInfos={queryInfos}
|
||||||
|
metadatas={metadatas}
|
||||||
|
value={content}
|
||||||
|
name={name}
|
||||||
|
rowId={rowId}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Text textColor="neutral800">{toString(formattedContent)}</Text>;
|
||||||
|
};
|
||||||
|
|
||||||
|
CellContent.defaultProps = {
|
||||||
|
content: undefined,
|
||||||
|
queryInfos: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
CellContent.propTypes = {
|
||||||
|
content: PropTypes.any,
|
||||||
|
fieldSchema: PropTypes.shape({ multiple: PropTypes.bool, type: PropTypes.string.isRequired })
|
||||||
|
.isRequired,
|
||||||
|
metadatas: PropTypes.object.isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
rowId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
|
queryInfos: PropTypes.shape({ endPoint: PropTypes.string.isRequired }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CellContent;
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
const formatDisplayedValue = (value, type, formatters) => {
|
||||||
|
let formattedValue = value;
|
||||||
|
|
||||||
|
if (type === 'date') {
|
||||||
|
formattedValue = formatters.formatDate(value, { dateStyle: 'full' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'datetime') {
|
||||||
|
formattedValue = formatters.formatDate(value, { dateStyle: 'full', timeStyle: 'short' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'time') {
|
||||||
|
const [hour, minute, second] = value.split(':');
|
||||||
|
const date = new Date();
|
||||||
|
date.setHours(hour);
|
||||||
|
date.setMinutes(minute);
|
||||||
|
date.setSeconds(second);
|
||||||
|
|
||||||
|
formattedValue = formatters.formatTime(date, {
|
||||||
|
numeric: 'auto',
|
||||||
|
style: 'short',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['float', 'integer', 'biginteger', 'decimal'].includes(type)) {
|
||||||
|
formattedValue = formatters.formatNumber(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return formattedValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default formatDisplayedValue;
|
||||||
@ -1,13 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { BaseCheckbox, Box, IconButton, Tbody, Td, Text, Tr, Row } from '@strapi/parts';
|
import { BaseCheckbox, Box, IconButton, Tbody, Td, Tr, Row } from '@strapi/parts';
|
||||||
import { EditIcon, DeleteIcon, Duplicate } from '@strapi/icons';
|
import { EditIcon, DeleteIcon, Duplicate } from '@strapi/icons';
|
||||||
import { useTracking } from '@strapi/helper-plugin';
|
import { useTracking } from '@strapi/helper-plugin';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { usePluginsQueryParams } from '../../../hooks';
|
import { usePluginsQueryParams } from '../../../hooks';
|
||||||
// import { Tooltip } from '@strapi/parts/Tooltip';
|
import CellContent from '../CellContent';
|
||||||
// import toString from 'lodash/toString';
|
|
||||||
|
|
||||||
const TableRows = ({
|
const TableRows = ({
|
||||||
canCreate,
|
canCreate,
|
||||||
@ -25,6 +24,7 @@ const TableRows = ({
|
|||||||
location: { pathname },
|
location: { pathname },
|
||||||
} = useHistory();
|
} = useHistory();
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
const { trackUsage } = useTracking();
|
const { trackUsage } = useTracking();
|
||||||
const pluginsQueryParams = usePluginsQueryParams();
|
const pluginsQueryParams = usePluginsQueryParams();
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ const TableRows = ({
|
|||||||
{typeof cellFormatter === 'function' ? (
|
{typeof cellFormatter === 'function' ? (
|
||||||
cellFormatter(data, { key, name, ...rest })
|
cellFormatter(data, { key, name, ...rest })
|
||||||
) : (
|
) : (
|
||||||
<Text textColor="neutral800">{data[name] || '-'}</Text>
|
<CellContent content={data[name]} name={name} {...rest} rowId={data.id} />
|
||||||
)}
|
)}
|
||||||
</Td>
|
</Td>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -169,7 +169,7 @@ function ListView({
|
|||||||
'{number, plural, =1 {# entry has} other {# entries have}} successfully been loaded',
|
'{number, plural, =1 {# entry has} other {# entries have}} successfully been loaded',
|
||||||
},
|
},
|
||||||
// Using the plural form
|
// Using the plural form
|
||||||
{ number: 2 }
|
{ number: pagination.count }
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -480,6 +480,7 @@
|
|||||||
"content-manager.containers.Edit.returnList": "Return to list",
|
"content-manager.containers.Edit.returnList": "Return to list",
|
||||||
"content-manager.containers.Edit.seeDetails": "Details",
|
"content-manager.containers.Edit.seeDetails": "Details",
|
||||||
"content-manager.containers.Edit.submit": "Save",
|
"content-manager.containers.Edit.submit": "Save",
|
||||||
|
"content-manager.popover.display-relations.label": "Display relations",
|
||||||
"content-manager.containers.EditSettingsView.modal-form.edit-field": "Edit the field",
|
"content-manager.containers.EditSettingsView.modal-form.edit-field": "Edit the field",
|
||||||
"content-manager.containers.EditView.add.new": "ADD NEW ENTRY",
|
"content-manager.containers.EditView.add.new": "ADD NEW ENTRY",
|
||||||
"content-manager.containers.EditView.components.missing.plural": "There is {count} missing components",
|
"content-manager.containers.EditView.components.missing.plural": "There is {count} missing components",
|
||||||
@ -495,8 +496,7 @@
|
|||||||
"content-manager.pages.ListView.header-subtitle": "{number, plural, =0 {# entries} one {# entry} other {# entries}} found",
|
"content-manager.pages.ListView.header-subtitle": "{number, plural, =0 {# entries} one {# entry} other {# entries}} found",
|
||||||
"content-manager.containers.List.published": "Published",
|
"content-manager.containers.List.published": "Published",
|
||||||
"content-manager.containers.ListPage.displayedFields": "Displayed Fields",
|
"content-manager.containers.ListPage.displayedFields": "Displayed Fields",
|
||||||
"content-manager.containers.ListPage.items.plural": "items",
|
"content-manager.containers.ListPage.items": "{number, plural, =0 {items} one {item} other {items}}",
|
||||||
"content-manager.containers.ListPage.items.singular": "item",
|
|
||||||
"content-manager.containers.ListPage.table-headers.published_at": "State",
|
"content-manager.containers.ListPage.table-headers.published_at": "State",
|
||||||
"content-manager.containers.ListSettingsView.modal-form.edit-label": "Edit the label",
|
"content-manager.containers.ListSettingsView.modal-form.edit-label": "Edit the label",
|
||||||
"content-manager.containers.SettingPage.add.field": "Insert another field",
|
"content-manager.containers.SettingPage.add.field": "Insert another field",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user