diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json
index b71a4d03..b152514d 100644
--- a/public/locales/en/translation.json
+++ b/public/locales/en/translation.json
@@ -542,6 +542,22 @@
"name": "Name",
"compose": "Compose",
"upload": "Upload"
+ },
+ "embed": {
+ "tab": "Embed",
+ "no-embed": "To add an embed, click on",
+ "allow": "Enable",
+ "allow-display-data-embed": "Disable",
+ "all-fields": "Embeds",
+ "icon": "Icon",
+ "title": "Embed title",
+ "title-help": "",
+ "src": "Address",
+ "src-help": "Embed address (iframe)",
+ "preview": "Preview",
+ "fullscreen": "Fullscreen",
+ "width": "Width (px)",
+ "height": "Height (px)"
}
}
},
diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json
index 011fa295..766d2d10 100644
--- a/public/locales/fr/translation.json
+++ b/public/locales/fr/translation.json
@@ -594,6 +594,22 @@
"name": "Nom",
"compose": "Composer",
"upload": "Envoyer"
+ },
+ "embed": {
+ "tab": "Inclusions",
+ "no-embed": "Pour activer les inclusions, cliquer sur",
+ "allow": "Activer",
+ "allow-display-data-embed": "Désactiver",
+ "all-fields": "Inclusions",
+ "icon": "Icône",
+ "title": "Titre de l'inclusion",
+ "title-help": "",
+ "src": "Adresse",
+ "src-help": "Adresse de la page à inclure (iframe)",
+ "preview": "Prévisualiser",
+ "fullscreen": "Plein écran",
+ "width": "Largeur (px)",
+ "height": "Hauteur (px)"
}
}
},
diff --git a/src/components/BPIcon.js b/src/components/BPIcon.js
new file mode 100644
index 00000000..c1085f48
--- /dev/null
+++ b/src/components/BPIcon.js
@@ -0,0 +1,71 @@
+import React from 'react';
+import { Icon } from '@blueprintjs/core';
+
+export const graphIcons = [
+ 'chart',
+ 'curved-range-chart',
+ 'database',
+ 'diagram-tree',
+ 'doughnut-chart',
+ 'flow-branch',
+ 'flow-end',
+ 'flow-linear',
+ 'flow-review',
+ 'flow-review-branch',
+ 'flows',
+ 'form',
+ 'full-stacked-chart',
+ 'gantt-chart',
+ 'graph',
+ 'grid',
+ 'grouped-bar-chart',
+ 'heat-grid',
+ 'heatmap',
+ 'horizontal-bar-chart',
+ 'horizontal-bar-chart-asc',
+ 'horizontal-bar-chart-desc',
+ 'layout',
+ 'layout-auto',
+ 'layout-balloon',
+ 'layout-circle',
+ 'layout-grid',
+ 'layout-group-by',
+ 'layout-hierarchy',
+ 'layout-linear',
+ 'layout-skew-grid',
+ 'layout-sorted-clusters',
+ 'many-to-many',
+ 'many-to-one',
+ 'one-to-many',
+ 'one-to-one',
+ 'pie-chart',
+ 'polygon-filter',
+ 'regression-chart',
+ 'scatter-plot',
+ 'series-add',
+ 'series-configuration',
+ 'series-derived',
+ 'series-filtered',
+ 'series-search',
+ 'stacked-chart',
+ 'step-chart',
+ 'timeline-area-chart',
+ 'timeline-bar-chart',
+ 'timeline-line-chart',
+ 'trending-down',
+ 'trending-up',
+ 'vertical-bar-chart-asc',
+ 'vertical-bar-chart-desc',
+ 'waterfall-chart',
+].sort();
+
+const BPIcon = ({ icon, displayIconName, style = {}, ...rest }) =>
+ (displayIconName ? (
+ <>
+ {icon}
+ >
+ ) : (
+
+ ));
+
+export default BPIcon;
diff --git a/src/modules/RA/DataLayer/components/DataLayerForm.js b/src/modules/RA/DataLayer/components/DataLayerForm.js
index 82e89cb1..84a4cbec 100644
--- a/src/modules/RA/DataLayer/components/DataLayerForm.js
+++ b/src/modules/RA/DataLayer/components/DataLayerForm.js
@@ -13,6 +13,7 @@ import MinisheetTab from './tabs/MinisheetTab';
import FilterTab from './tabs/FilterTab';
import TableTab from './tabs/TableTab';
import StyleImageField from './StyleImageField';
+import EmbedTab from './tabs/EmbedTab';
const initialErrorState = {
definition: false,
@@ -22,6 +23,7 @@ const initialErrorState = {
minisheet: false,
filter: false,
table: false,
+ embed: false,
};
const inErrorReducer = (state, { type, payload }) => {
@@ -91,6 +93,10 @@ const DataLayerForm = React.memo(props => {
dispatch({ type: 'minisheet', payload: inError });
}, []);
+ const onEmbedErrorChange = React.useCallback(() => {
+ dispatch({ type: 'embed', paylaod: false });
+ }, []);
+
const onTableErrorChange = React.useCallback(({
values: { fields = [], table_enable: tableEnable },
}) => {
@@ -205,6 +211,16 @@ const DataLayerForm = React.memo(props => {
+
+
+
+
);
});
diff --git a/src/modules/RA/DataLayer/components/tabs/EmbedTab/EmbedConfigField.js b/src/modules/RA/DataLayer/components/tabs/EmbedTab/EmbedConfigField.js
new file mode 100644
index 00000000..39725468
--- /dev/null
+++ b/src/modules/RA/DataLayer/components/tabs/EmbedTab/EmbedConfigField.js
@@ -0,0 +1,45 @@
+import React from 'react';
+import {
+ useTranslate,
+ useInput,
+ ArrayInput,
+ SimpleFormIterator,
+} from 'react-admin';
+import Typography from '@material-ui/core/Typography';
+
+import EmbedItemInput from './EmbedItemInput';
+
+const EmbedConfigField = ({ label, ...rest }) => {
+ const translate = useTranslate();
+ const {
+ meta: { error },
+ } = useInput(rest);
+
+ return (
+ <>
+
+ {translate(label)}
+
+
+ {error?.length > 0 &&
+ error.flatMap(
+ err =>
+ err &&
+ Object.entries(err).map(([key, value]) => (
+
+ {key}: {translate(value)}
+
+ )),
+ )}
+
+ >
+ );
+};
+
+export default EmbedConfigField;
diff --git a/src/modules/RA/DataLayer/components/tabs/EmbedTab/EmbedItemInput.js b/src/modules/RA/DataLayer/components/tabs/EmbedTab/EmbedItemInput.js
new file mode 100644
index 00000000..288d8c93
--- /dev/null
+++ b/src/modules/RA/DataLayer/components/tabs/EmbedTab/EmbedItemInput.js
@@ -0,0 +1,111 @@
+import React, { useEffect } from 'react';
+import { BooleanInput, NumberInput, SelectInput, TextInput, useTranslate } from 'react-admin';
+
+import {
+ Accordion,
+ AccordionDetails,
+ AccordionSummary,
+ Typography,
+} from '@material-ui/core';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import { useField } from 'react-final-form';
+import Condition from '../../../../../../components/react-admin/Condition';
+import BPIcon, { graphIcons } from '../../../../../../components/BPIcon';
+
+const EmbedItemInput = ({ source }) => {
+ const [previewExpanded, setPreviewExpanded] = React.useState(false);
+ const translate = useTranslate();
+
+ const iconChoices = React.useMemo(
+ () =>
+ graphIcons.map(bpIcon => ({
+ id: bpIcon,
+ name: ,
+ })),
+ [],
+ );
+
+ const {
+ input: { value: url },
+ } = useField(`${source}.src`);
+
+ useEffect(() => {
+ setPreviewExpanded(false);
+ }, [url]);
+
+ return (
+
+
+ ,
+ }}
+ style={{ width: '5em', minWidth: '5em' }}
+ />
+
+
+
+
+
val.match(/(^(https?:)?\/\/.)/)}
+ >
+ setPreviewExpanded(val)}
+ style={{ width: '40em', marginBottom: '2em' }}
+ >
+ }>
+ {translate('datalayer.form.embed.preview')}
+
+
+ {previewExpanded && (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default EmbedItemInput;
diff --git a/src/modules/RA/DataLayer/components/tabs/EmbedTab/index.js b/src/modules/RA/DataLayer/components/tabs/EmbedTab/index.js
new file mode 100644
index 00000000..1b1268af
--- /dev/null
+++ b/src/modules/RA/DataLayer/components/tabs/EmbedTab/index.js
@@ -0,0 +1,70 @@
+import React from 'react';
+
+import { BooleanInput, useTranslate } from 'react-admin';
+import { useField } from 'react-final-form';
+
+import Typography from '@material-ui/core/Typography';
+import Placeholder from '../../../../../../components/Placeholder';
+
+import EmbedConfigField from './EmbedConfigField';
+
+const validateEmbedFields = data => {
+ const valid = !data.some(({ label }) => label && !label.length);
+ if (!valid) {
+ return 'datalayer.form.embed.row-in-error';
+ }
+ return undefined;
+};
+
+const EmbedConfigTabContent = props => {
+ const { input: { value: embedEnable, onChange: onEmbedEnableChange } } = useField('settings.embed_enable');
+ const { input: { value: source } } = useField('source');
+ const { input: { value: embedExportEnable } } = useField('embed_export_enable');
+ const translate = useTranslate();
+
+ if (!source) {
+ return (
+
+
+ {translate('datalayer.form.embed.no-source')}
+
+
+ );
+ }
+
+ // No embed yet
+ if (!embedEnable) {
+ return (
+
+
+ {translate('datalayer.form.embed.no-embed')}
+
+
+
+ );
+ }
+
+ return (
+ <>
+
+
+ >
+ );
+};
+
+
+export default EmbedConfigTabContent;