design-comuni-plone-theme 11.24.3 → 11.24.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
 
2
2
 
3
+ ## [11.24.5](https://github.com/RedTurtle/design-comuni-plone-theme/compare/v11.24.4...v11.24.5) (2024-11-22)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * added info on contents file upload modal on restraint in servizio-modulistica folder ([#796](https://github.com/RedTurtle/design-comuni-plone-theme/issues/796)) ([cb7b3c8](https://github.com/RedTurtle/design-comuni-plone-theme/commit/cb7b3c83325f6aa3da94faa29eaf0c940e216a93))
9
+ * removed whole day condition in page header subtitle ([#800](https://github.com/RedTurtle/design-comuni-plone-theme/issues/800)) ([cc7d668](https://github.com/RedTurtle/design-comuni-plone-theme/commit/cc7d6686dc91aaaf3eaef51102c8e035540efe46))
10
+ * safari rendering issues and overhaul old dynamic bootstrap italia icons import using cache map ([#810](https://github.com/RedTurtle/design-comuni-plone-theme/issues/810)) ([9c23ac6](https://github.com/RedTurtle/design-comuni-plone-theme/commit/9c23ac6fd172f31c0aa4723d4db008a92100b1a1))
11
+ * updated lockfile ([8d1cf74](https://github.com/RedTurtle/design-comuni-plone-theme/commit/8d1cf74defdec9059dff9a1e1b4313fa7b4c0402))
12
+ * updated volto-gdpr-privacy addon version to 2.2.9([#806](https://github.com/RedTurtle/design-comuni-plone-theme/issues/806)) ([f785ddd](https://github.com/RedTurtle/design-comuni-plone-theme/commit/f785ddd651e1528439a58852f852a9331df2a57e))
13
+
14
+
15
+ ### Maintenance
16
+
17
+ * removed additional info from release.md from september ([#799](https://github.com/RedTurtle/design-comuni-plone-theme/issues/799)) ([60052e7](https://github.com/RedTurtle/design-comuni-plone-theme/commit/60052e77b71a9f9dbb59714240acadc01e14ee0a))
18
+
19
+
20
+ ### Documentation
21
+
22
+ * updated publiccode and release log ([6a5e490](https://github.com/RedTurtle/design-comuni-plone-theme/commit/6a5e490248df7e53784b5f730b096ab9d6553ad8))
23
+
24
+ ## [11.24.4](https://github.com/RedTurtle/design-comuni-plone-theme/compare/v11.24.3...v11.24.4) (2024-11-07)
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * arlogin styles in 992px-1200px media query space ([#802](https://github.com/RedTurtle/design-comuni-plone-theme/issues/802)) ([eebf6e4](https://github.com/RedTurtle/design-comuni-plone-theme/commit/eebf6e4129c021dc361638c940b62b67a5b15739))
30
+ * page freeze when updateSideMenuOnLoadingBlocks=true and page has gallery ([#805](https://github.com/RedTurtle/design-comuni-plone-theme/issues/805)) ([cab333e](https://github.com/RedTurtle/design-comuni-plone-theme/commit/cab333e35dc7faac5fbc61a41fdec02922378b00))
31
+
32
+
33
+ ### Documentation
34
+
35
+ * update docs link in publiccode.yml ([#190](https://github.com/RedTurtle/design-comuni-plone-theme/issues/190)) ([34a35b2](https://github.com/RedTurtle/design-comuni-plone-theme/commit/34a35b2ac7c6301e1bbf22a6109fef8d8135db3f))
36
+ * updated publiccode and release log ([67a062c](https://github.com/RedTurtle/design-comuni-plone-theme/commit/67a062cf007333435046c1b3cf8cf0d34bf59abc))
37
+
3
38
  ## [11.24.3](https://github.com/RedTurtle/design-comuni-plone-theme/compare/v11.24.2...v11.24.3) (2024-10-24)
4
39
 
5
40
 
package/RELEASE.md CHANGED
@@ -39,7 +39,25 @@
39
39
  ### Fix
40
40
 
41
41
  - ...
42
- -->
42
+ -->
43
+
44
+ ## Versione 11.24.5 (22/11/2024)
45
+
46
+ ### Migliorie
47
+
48
+ - Inserito messaggio di avviso quando si tenta di caricare un file dalla cartella Modulistica all'interno di un Servizio per segnalare limitazione sull'upload
49
+
50
+ ### Fix
51
+
52
+ - L'impostazione "Solo cookie tecnici" non causa problemi nell'apertura del cookie banner.
53
+ - [WebKit, Safari, iOS] Risolto un problema di visualizzazione grafica di alcuni bottoni che contengono al loro interno un link ad un sito esterno.
54
+ - Quando un evento ha impostata l'opzione "Tutta la giornata", le date sotto il titolo vengono visualizzate in maniera corretta.
55
+
56
+ ## Versione 11.24.4 (07/11/2024)
57
+
58
+ ### Fix
59
+
60
+ - Risolto un problema di visualizzazione grafica per il bottone di login all'area personale per alcune specifiche dimensioni di schermi
43
61
 
44
62
  ## Versione 11.24.3 (24/10/2024)
45
63
 
@@ -91,7 +109,7 @@
91
109
 
92
110
  ### Fix
93
111
 
94
- - Rimosso il campo "ID lighthouse" dal blocco elenco con variazione Card con Testo Animato perchè entra in contrasto con asseveratore. Pianificato evento per ripristinarlo.
112
+ - Rimosso il campo "ID lighthouse" dal blocco elenco con variazione Card con Testo Animato perchè entra in contrasto con asseveratore
95
113
 
96
114
  ## Versione 11.22.0 (05/09/2024)
97
115
 
@@ -2644,6 +2644,11 @@ msgstr ""
2644
2644
  msgid "modulistica"
2645
2645
  msgstr ""
2646
2646
 
2647
+ #: overrideTranslations
2648
+ # defaultMessage: As per the official information architecture outlined in measure 1.4.1, all forms must be properly uploaded in the designated section within Amministrazione > Documenti e Dati > Modulistica, and linked to the relevant service sheet. It is no longer possible to upload files and attachments directly into this container.
2649
+ msgid "modulistica_restraint"
2650
+ msgstr ""
2651
+
2647
2652
  #: components/ItaliaTheme/View/Commons/DownloadFileFormat
2648
2653
  # defaultMessage: Scarica il file
2649
2654
  msgid "modulo_download_file"
@@ -2629,6 +2629,11 @@ msgstr "Last update"
2629
2629
  msgid "modulistica"
2630
2630
  msgstr "Forms"
2631
2631
 
2632
+ #: overrideTranslations
2633
+ # defaultMessage: As per the official information architecture outlined in measure 1.4.1, all forms must be properly uploaded in the designated section within Amministrazione > Documenti e Dati > Modulistica, and linked to the relevant service sheet. It is no longer possible to upload files and attachments directly into this container.
2634
+ msgid "modulistica_restraint"
2635
+ msgstr ""
2636
+
2632
2637
  #: components/ItaliaTheme/View/Commons/DownloadFileFormat
2633
2638
  # defaultMessage: Scarica il file
2634
2639
  msgid "modulo_download_file"
@@ -2638,6 +2638,11 @@ msgstr "Última actualización"
2638
2638
  msgid "modulistica"
2639
2639
  msgstr "Formularios"
2640
2640
 
2641
+ #: overrideTranslations
2642
+ # defaultMessage: As per the official information architecture outlined in measure 1.4.1, all forms must be properly uploaded in the designated section within Amministrazione > Documenti e Dati > Modulistica, and linked to the relevant service sheet. It is no longer possible to upload files and attachments directly into this container.
2643
+ msgid "modulistica_restraint"
2644
+ msgstr ""
2645
+
2641
2646
  #: components/ItaliaTheme/View/Commons/DownloadFileFormat
2642
2647
  # defaultMessage: Scarica il file
2643
2648
  msgid "modulo_download_file"
@@ -2646,6 +2646,11 @@ msgstr "Dernière mise à jour"
2646
2646
  msgid "modulistica"
2647
2647
  msgstr "Formes"
2648
2648
 
2649
+ #: overrideTranslations
2650
+ # defaultMessage: As per the official information architecture outlined in measure 1.4.1, all forms must be properly uploaded in the designated section within Amministrazione > Documenti e Dati > Modulistica, and linked to the relevant service sheet. It is no longer possible to upload files and attachments directly into this container.
2651
+ msgid "modulistica_restraint"
2652
+ msgstr ""
2653
+
2649
2654
  #: components/ItaliaTheme/View/Commons/DownloadFileFormat
2650
2655
  # defaultMessage: Scarica il file
2651
2656
  msgid "modulo_download_file"
@@ -2629,6 +2629,11 @@ msgstr "Ultimo aggiornamento"
2629
2629
  msgid "modulistica"
2630
2630
  msgstr "Modulistica"
2631
2631
 
2632
+ #: overrideTranslations
2633
+ # defaultMessage: As per the official information architecture outlined in measure 1.4.1, all forms must be properly uploaded in the designated section within Amministrazione > Documenti e Dati > Modulistica, and linked to the relevant service sheet. It is no longer possible to upload files and attachments directly into this container.
2634
+ msgid "modulistica_restraint"
2635
+ msgstr "Come da architettura informativa ufficiale prevista dalla misura 1.4.1, tutta la modulistica dovrà essere correttamente caricata nella sezione apposita, all'interno di amministrazione, documenti e dati, modulistica, e relazionata con la scheda servizio. Non è più possibile caricare file ed allegati direttamente in questo contenitore."
2636
+
2632
2637
  #: components/ItaliaTheme/View/Commons/DownloadFileFormat
2633
2638
  # defaultMessage: Scarica il file
2634
2639
  msgid "modulo_download_file"
package/locales/volto.pot CHANGED
@@ -1,7 +1,7 @@
1
1
  msgid ""
2
2
  msgstr ""
3
3
  "Project-Id-Version: Plone\n"
4
- "POT-Creation-Date: 2024-09-26T08:07:45.909Z\n"
4
+ "POT-Creation-Date: 2024-10-29T14:58:46.664Z\n"
5
5
  "Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
6
6
  "Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
7
7
  "MIME-Version: 1.0\n"
@@ -2631,6 +2631,11 @@ msgstr ""
2631
2631
  msgid "modulistica"
2632
2632
  msgstr ""
2633
2633
 
2634
+ #: overrideTranslations
2635
+ # defaultMessage: As per the official information architecture outlined in measure 1.4.1, all forms must be properly uploaded in the designated section within Amministrazione > Documenti e Dati > Modulistica, and linked to the relevant service sheet. It is no longer possible to upload files and attachments directly into this container.
2636
+ msgid "modulistica_restraint"
2637
+ msgstr ""
2638
+
2634
2639
  #: components/ItaliaTheme/View/Commons/DownloadFileFormat
2635
2640
  # defaultMessage: Scarica il file
2636
2641
  msgid "modulo_download_file"
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "design-comuni-plone-theme",
3
3
  "description": "Volto Theme for Italia design guidelines",
4
4
  "license": "GPL-v3",
5
- "version": "11.24.3",
5
+ "version": "11.24.5",
6
6
  "main": "src/index.js",
7
7
  "repository": {
8
8
  "type": "git",
@@ -153,7 +153,7 @@
153
153
  "volto-editablefooter": "5.1.7",
154
154
  "volto-feedback": "0.3.2",
155
155
  "volto-form-block": "3.10.0",
156
- "volto-gdpr-privacy": "2.2.7",
156
+ "volto-gdpr-privacy": "2.2.9",
157
157
  "volto-google-analytics": "2.0.0",
158
158
  "volto-multilingual-widget": "3.2.1",
159
159
  "volto-querywidget-with-browser": "0.4.2",
package/publiccode.yml CHANGED
@@ -20,7 +20,7 @@ logo: docs/logo-io-comune.png
20
20
  description:
21
21
  it:
22
22
  documentation: |-
23
- https://docs.google.com/document/d/1SThuxa_ah0BuNXukWs564kKPfprK41WLQE8Mome-0xg/
23
+ https://docs.google.com/document/d/1BrlGYmE3Z4y6FMIrfBJWOX1P2JVEGzJZS6TRbeIiFSk/edit?tab=t.0
24
24
  features:
25
25
  - PNRR
26
26
  - PNRR/Misura/1.2
@@ -227,9 +227,9 @@ maintenance:
227
227
  name: io-Comune - Il sito AgID per Comuni ed Enti Pubblici
228
228
  platforms:
229
229
  - web
230
- releaseDate: '2024-10-24'
230
+ releaseDate: '2024-11-22'
231
231
  softwareType: standalone/web
232
- softwareVersion: 11.24.3
232
+ softwareVersion: 11.24.5
233
233
  url: 'https://github.com/italia/design-comuni-plone-theme'
234
234
  usedBy:
235
235
  - ASP Comuni Modenesi Area Nord
@@ -9,7 +9,7 @@ import { Button } from 'design-react-kit';
9
9
  const LoginButton = ({ children, baseLoginUrl, size = 'full' }) => {
10
10
  return baseLoginUrl ? (
11
11
  <Button
12
- className="btn-icon"
12
+ className="btn-icon login-button"
13
13
  color="primary"
14
14
  href={baseLoginUrl}
15
15
  icon={false}
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useRef, useMemo } from 'react';
1
+ import React, { useState, useEffect } from 'react';
2
2
  import { v4 as uuid } from 'uuid';
3
3
  import PropTypes from 'prop-types';
4
4
 
@@ -12,50 +12,101 @@ const propTypes = {
12
12
 
13
13
  const defaultProps = {
14
14
  color: '',
15
- size: '',
15
+ size: '24px',
16
16
  icon: '',
17
17
  padding: false,
18
18
  };
19
19
 
20
+ // No ts means we get many different things here, standardize it
21
+ const SIZE_MAPPINGS = {
22
+ xs: '1rem',
23
+ sm: '1.25rem',
24
+ md: defaultProps.size,
25
+ lg: '1.75rem',
26
+ xl: '2rem',
27
+ };
28
+
29
+ function getIconMapSizeConfig(size) {
30
+ const mapKeys = Object.keys(SIZE_MAPPINGS);
31
+ if (mapKeys.includes(size)) return SIZE_MAPPINGS[size];
32
+ return size;
33
+ }
34
+
35
+ const iconCache = new Map(); // Global cache using Map
36
+
20
37
  const Icon = ({ icon, title, className, size }) => {
21
- const ImportedIconRef = useRef(null);
22
- const [loading, setLoading] = useState(false);
23
- const iconID = useMemo(() => uuid(), []);
38
+ const [iconState, setIconState] = useState({
39
+ loading: true,
40
+ icon: undefined,
41
+ // Move to useId in react18
42
+ id: uuid(),
43
+ });
24
44
 
25
45
  useEffect(() => {
26
- setLoading(true);
27
- const importIcon = async () => {
28
- try {
29
- const { default: namedImport } = await import(
30
- `bootstrap-italia/src/svg/${icon}.svg`
31
- );
32
- ImportedIconRef.current = namedImport;
33
- } catch (err) {
34
- throw err;
35
- } finally {
36
- setLoading(false);
37
- }
38
- };
39
- importIcon();
46
+ let loadableIcon = iconCache.get(icon);
47
+ // Use the cached icon if available
48
+ if (loadableIcon) {
49
+ setIconState((prev) => ({
50
+ ...prev,
51
+ loading: false,
52
+ icon: loadableIcon,
53
+ }));
54
+ } else {
55
+ // Otherwise, dynamically import the icon
56
+ const importIcon = async () => {
57
+ try {
58
+ const { default: namedImport } = await import(
59
+ `bootstrap-italia/src/svg/${icon}.svg`
60
+ );
61
+ iconCache.set(icon, namedImport); // Cache the imported icon
62
+ loadableIcon = namedImport;
63
+ } catch (err) {
64
+ console.error(`Error loading icon: ${icon}`, err);
65
+ } finally {
66
+ setIconState((prev) => ({
67
+ ...prev,
68
+ loading: false,
69
+ icon: loadableIcon,
70
+ }));
71
+ }
72
+ };
73
+ importIcon();
74
+ }
40
75
  }, [icon]);
41
76
 
42
- if (!loading && ImportedIconRef.current) {
43
- const { current: name } = ImportedIconRef;
77
+ const iconSize = getIconMapSizeConfig(size);
78
+
79
+ // Placeholder that is shown while the icon is loading
80
+ if (iconState.loading) {
81
+ return (
82
+ <span
83
+ style={{
84
+ width: iconSize,
85
+ height: iconSize,
86
+ backgroundColor: 'transparent',
87
+ }}
88
+ className={className}
89
+ />
90
+ );
91
+ }
92
+
93
+ // Render the icon once it's loaded
94
+ if (iconState.icon) {
44
95
  return (
45
96
  <svg
46
- xmlns={name.attributes?.xmlns}
47
- viewBox={name.attributes?.viewBox}
48
- width={name.attributes?.width}
49
- height={name.attributes?.height}
50
- style={{ height: size, width: 'auto' }}
97
+ xmlns={iconState.icon.attributes?.xmlns}
98
+ viewBox={iconState.icon.attributes?.viewBox}
99
+ width={iconState.icon.attributes?.width}
100
+ height={iconState.icon.attributes?.height}
101
+ style={{ height: iconSize, width: iconSize }}
51
102
  className={className}
52
103
  aria-hidden="true"
53
104
  dangerouslySetInnerHTML={{
54
105
  __html: title
55
- ? `<title id="${iconID}">${title}</title>${name.content}`
56
- : name.content,
106
+ ? `<title id="${iconState.id}">${title}</title>${iconState.icon.content}`
107
+ : iconState.icon.content,
57
108
  }}
58
- aria-labelledby={iconID}
109
+ aria-labelledby={iconState.id}
59
110
  />
60
111
  );
61
112
  }
@@ -36,12 +36,12 @@ const FontAwesomeIcon = (props) => {
36
36
  prefixKey === 'fab'
37
37
  ? 'brands'
38
38
  : prefixKey === 'far'
39
- ? 'regular'
40
- : prefixKey === 'fas'
41
- ? 'solid'
42
- : prefixKey != null
43
- ? prefixKey
44
- : 'solid',
39
+ ? 'regular'
40
+ : prefixKey === 'fas'
41
+ ? 'solid'
42
+ : prefixKey != null
43
+ ? prefixKey
44
+ : 'solid',
45
45
  iconName,
46
46
  ];
47
47
  };
@@ -12,6 +12,7 @@ import { FontAwesomeIcon } from 'design-comuni-plone-theme/components/ItaliaThem
12
12
 
13
13
  const Icon = (props) => {
14
14
  const { icon, className, color, size, padding, ...rest } = props;
15
+
15
16
  if (icon) {
16
17
  const classes = classNames(
17
18
  'icon',
@@ -83,9 +83,7 @@ const PageHeaderEventDates = ({ content, moment, rrule }) => {
83
83
  !openEnd &&
84
84
  !renderOnlyStart &&
85
85
  `dal ${Moment(content.start).format('DD-MM-Y')} al ${endDate}`}
86
- {(wholeDay ||
87
- renderOnlyStart ||
88
- Moment(content.end).isSame(actualEndDate)) &&
86
+ {(renderOnlyStart || Moment(content.end).isSame(actualEndDate)) &&
89
87
  !openEnd &&
90
88
  `${Moment(content.start).format('DD-MM-Y')}`}
91
89
  {openEnd &&
@@ -67,9 +67,8 @@ export const useSideMenu = (content, documentBody) => {
67
67
  }
68
68
  if (observer) {
69
69
  observer.observe(documentBody.current, {
70
- //attributes: true,
71
70
  childList: true,
72
- subtree: true,
71
+ //subtree: true, //commentato, perchè a noi interessano solo i figli di primo livello. Con questo abilitato, se in pagina ci sono delle gallery si impalla il browser
73
72
  });
74
73
  }
75
74
  return () => {
@@ -0,0 +1,373 @@
1
+ // CUSTOMIZATION:
2
+ // - 196-202 - 230-262: added file upload restraint message as per agid regulations
3
+
4
+ /**
5
+ * Contents upload modal.
6
+ * @module components/manage/Contents/ContentsUploadModal
7
+ */
8
+
9
+ import React, { Component } from 'react';
10
+ import PropTypes from 'prop-types';
11
+ import { connect } from 'react-redux';
12
+ import { compose } from 'redux';
13
+ import {
14
+ Button,
15
+ Dimmer,
16
+ Header,
17
+ Icon,
18
+ Image,
19
+ Loader,
20
+ Modal,
21
+ Table,
22
+ Segment,
23
+ TableCell,
24
+ } from 'semantic-ui-react';
25
+ import loadable from '@loadable/component';
26
+ import { concat, filter, map } from 'lodash';
27
+ import filesize from 'filesize';
28
+ import { readAsDataURL } from 'promise-file-reader';
29
+ import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
30
+ import { FormattedRelativeDate } from '@plone/volto/components';
31
+ import { createContent, getTypes } from '@plone/volto/actions';
32
+ import { validateFileUploadSize, getBaseUrl } from '@plone/volto/helpers';
33
+
34
+ const Dropzone = loadable(() => import('react-dropzone'));
35
+
36
+ const messages = defineMessages({
37
+ cancel: {
38
+ id: 'Cancel',
39
+ defaultMessage: 'Cancel',
40
+ },
41
+ upload: {
42
+ id: '{count, plural, one {Upload {count} file} other {Upload {count} files}}',
43
+ defaultMessage:
44
+ '{count, plural, one {Upload {count} file} other {Upload {count} files}}',
45
+ },
46
+ });
47
+
48
+ const SUBREQUEST = 'batch-upload';
49
+
50
+ /**
51
+ * ContentsUploadModal class.
52
+ * @class ContentsUploadModal
53
+ * @extends Component
54
+ */
55
+ class ContentsUploadModal extends Component {
56
+ /**
57
+ * Property types.
58
+ * @property {Object} propTypes Property types.
59
+ * @static
60
+ */
61
+ static propTypes = {
62
+ createContent: PropTypes.func.isRequired,
63
+ pathname: PropTypes.string.isRequired,
64
+ request: PropTypes.shape({
65
+ loading: PropTypes.bool,
66
+ loaded: PropTypes.bool,
67
+ }).isRequired,
68
+ open: PropTypes.bool.isRequired,
69
+ onOk: PropTypes.func.isRequired,
70
+ onCancel: PropTypes.func.isRequired,
71
+ getTypes: PropTypes.func,
72
+ };
73
+
74
+ /**
75
+ * Constructor
76
+ * @method constructor
77
+ * @param {Object} props Component properties
78
+ * @constructs ContentsUploadModal
79
+ */
80
+ constructor(props) {
81
+ super(props);
82
+ this.onRemoveFile = this.onRemoveFile.bind(this);
83
+ this.onDrop = this.onDrop.bind(this);
84
+ this.onCancel = this.onCancel.bind(this);
85
+ this.onSubmit = this.onSubmit.bind(this);
86
+ this.state = {
87
+ files: [],
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Component will receive props
93
+ * @method componentWillReceiveProps
94
+ * @param {Object} nextProps Next properties
95
+ * @returns {undefined}
96
+ */
97
+ UNSAFE_componentWillReceiveProps(nextProps) {
98
+ if (this.props.request.loading && nextProps.request.loaded) {
99
+ this.props.onOk();
100
+ this.setState({
101
+ files: [],
102
+ });
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Remove file handler
108
+ * @method onRemoveFile
109
+ * @param {Object} event Event object
110
+ * @returns {undefined}
111
+ */
112
+ onRemoveFile(event) {
113
+ this.setState({
114
+ files: filter(
115
+ this.state.files,
116
+ (file, index) =>
117
+ index !== parseInt(event.target.getAttribute('value'), 10),
118
+ ),
119
+ });
120
+ }
121
+
122
+ /**
123
+ * Drop handler
124
+ * @method onDrop
125
+ * @param {array} files File objects
126
+ * @returns {undefined}
127
+ */
128
+ onDrop = async (files) => {
129
+ const validFiles = [];
130
+ for (let i = 0; i < files.length; i++) {
131
+ if (validateFileUploadSize(files[i], this.props.intl.formatMessage)) {
132
+ await readAsDataURL(files[i]).then((data) => {
133
+ const fields = data.match(/^data:(.*);(.*),(.*)$/);
134
+ files[i].preview = fields[0];
135
+ });
136
+ validFiles.push(files[i]);
137
+ }
138
+ }
139
+ this.setState({
140
+ files: concat(this.state.files, validFiles),
141
+ });
142
+ };
143
+
144
+ /**
145
+ * Cancel handler
146
+ * @method onCancel
147
+ * @returns {undefined}
148
+ */
149
+ onCancel() {
150
+ this.props.onCancel();
151
+ this.setState({
152
+ files: [],
153
+ });
154
+ }
155
+
156
+ /**
157
+ * Submit handler
158
+ * @method onSubmit
159
+ * @returns {undefined}
160
+ */
161
+ onSubmit() {
162
+ Promise.all(map(this.state.files, (file) => readAsDataURL(file))).then(
163
+ (files) => {
164
+ this.props.createContent(
165
+ this.props.pathname,
166
+ map(this.state.files, (file, index) => {
167
+ const fields = files[index].match(/^data:(.*);(.*),(.*)$/);
168
+ const image = fields[1].split('/')[0] === 'image';
169
+ return {
170
+ '@type': image ? 'Image' : 'File',
171
+ title: file.name,
172
+ [image ? 'image' : 'file']: {
173
+ data: fields[3],
174
+ encoding: fields[2],
175
+ 'content-type': fields[1],
176
+ filename: file.name,
177
+ },
178
+ };
179
+ }),
180
+ SUBREQUEST,
181
+ );
182
+ },
183
+ );
184
+ }
185
+
186
+ componentDidMount() {
187
+ this.props.getTypes(getBaseUrl(this.props.pathname));
188
+ }
189
+
190
+ /**
191
+ * Render method.
192
+ * @method render
193
+ * @returns {string} Markup for the component.
194
+ */
195
+ render() {
196
+ // as per agid guidelines, files cannot be uploaded in modulistica folder inside ct servizio
197
+ // show restraint and hide upload button when page is called modulistica and when there's a restraint
198
+ // this is enough to identify this only case bc even if another page is called 'modulistica', it will have 'File'
199
+ // as addable type
200
+ const showFileRestraint =
201
+ this.props.pathname.includes('modulistica') &&
202
+ !this.props.types.some((type) => type.id === 'File');
203
+
204
+ return (
205
+ this.props.open && (
206
+ <Modal open={this.props.open}>
207
+ <Header>
208
+ <FormattedMessage id="Upload files" defaultMessage="Upload files" />
209
+ </Header>
210
+ <Dimmer active={this.props.request.loading}>
211
+ <Loader>
212
+ <FormattedMessage
213
+ id="Uploading files"
214
+ defaultMessage="Uploading files"
215
+ />
216
+ </Loader>
217
+ </Dimmer>
218
+ <Modal.Content>
219
+ <Dropzone
220
+ onDrop={this.onDrop}
221
+ className="dropzone"
222
+ noDragEventsBubbling={true}
223
+ multiple={true}
224
+ >
225
+ {({ getRootProps, getInputProps }) => (
226
+ <div {...getRootProps({ className: 'dashed' })}>
227
+ <Segment>
228
+ <Table basic="very">
229
+ <Table.Body>
230
+ {showFileRestraint ? (
231
+ <Table.Row>
232
+ <TableCell>
233
+ <FormattedMessage
234
+ id="modulistica_restraint"
235
+ defaultMessage="As per the official information architecture outlined in measure 1.4.1, all forms must be properly uploaded in the designated section within Amministrazione > Documenti e Dati > Modulistica, and linked to the relevant service sheet. It is no longer possible to upload files and attachments directly into this container."
236
+ />
237
+ </TableCell>
238
+ </Table.Row>
239
+ ) : (
240
+ <Table.Row>
241
+ <Table.Cell>
242
+ <FormattedMessage
243
+ id="Drag and drop files from your computer onto this area or click the “Browse” button."
244
+ defaultMessage="Drag and drop files from your computer onto this area or click the “Browse” button."
245
+ />
246
+ </Table.Cell>
247
+ <Table.Cell>
248
+ <Button className="ui button primary">
249
+ <FormattedMessage
250
+ id="Browse"
251
+ defaultMessage="Browse"
252
+ />
253
+ </Button>
254
+ <input
255
+ {...getInputProps({
256
+ type: 'file',
257
+ style: { display: 'none' },
258
+ })}
259
+ />
260
+ </Table.Cell>
261
+ </Table.Row>
262
+ )}
263
+ </Table.Body>
264
+ </Table>
265
+ </Segment>
266
+ </div>
267
+ )}
268
+ </Dropzone>
269
+ {this.state.files.length > 0 && (
270
+ <Table compact singleLine>
271
+ <Table.Header>
272
+ <Table.Row>
273
+ <Table.HeaderCell width={8}>
274
+ <FormattedMessage
275
+ id="Filename"
276
+ defaultMessage="Filename"
277
+ />
278
+ </Table.HeaderCell>
279
+ <Table.HeaderCell width={4}>
280
+ <FormattedMessage
281
+ id="Last modified"
282
+ defaultMessage="Last modified"
283
+ />
284
+ </Table.HeaderCell>
285
+ <Table.HeaderCell width={4}>
286
+ <FormattedMessage
287
+ id="File size"
288
+ defaultMessage="File size"
289
+ />
290
+ </Table.HeaderCell>
291
+ <Table.HeaderCell width={4}>
292
+ <FormattedMessage id="Preview" defaultMessage="Preview" />
293
+ </Table.HeaderCell>
294
+ <Table.HeaderCell />
295
+ </Table.Row>
296
+ </Table.Header>
297
+ <Table.Body>
298
+ {map(this.state.files, (file, index) => (
299
+ <Table.Row className="upload-row" key={file.name}>
300
+ <Table.Cell>{file.name}</Table.Cell>
301
+ <Table.Cell>
302
+ {file.lastModifiedDate && (
303
+ <FormattedRelativeDate date={file.lastModifiedDate} />
304
+ )}
305
+ </Table.Cell>
306
+ <Table.Cell>
307
+ {filesize(file.size, { round: 0 })}
308
+ </Table.Cell>
309
+ <Table.Cell>
310
+ {file.type.split('/')[0] === 'image' && (
311
+ <Image src={file.preview} height={60} />
312
+ )}
313
+ </Table.Cell>
314
+ <Table.Cell>
315
+ <Icon
316
+ name="close"
317
+ value={index}
318
+ link
319
+ onClick={this.onRemoveFile}
320
+ />
321
+ </Table.Cell>
322
+ </Table.Row>
323
+ ))}
324
+ </Table.Body>
325
+ </Table>
326
+ )}
327
+ </Modal.Content>
328
+ <Modal.Actions>
329
+ {this.state.files.length > 0 && (
330
+ <Button
331
+ basic
332
+ circular
333
+ primary
334
+ floated="right"
335
+ icon="arrow right"
336
+ aria-label={this.props.intl.formatMessage(messages.upload, {
337
+ count: this.state.files.length,
338
+ })}
339
+ onClick={this.onSubmit}
340
+ title={this.props.intl.formatMessage(messages.upload, {
341
+ count: this.state.files.length,
342
+ })}
343
+ size="big"
344
+ />
345
+ )}
346
+ <Button
347
+ basic
348
+ circular
349
+ secondary
350
+ icon="remove"
351
+ aria-label={this.props.intl.formatMessage(messages.cancel)}
352
+ title={this.props.intl.formatMessage(messages.cancel)}
353
+ floated="right"
354
+ size="big"
355
+ onClick={this.onCancel}
356
+ />
357
+ </Modal.Actions>
358
+ </Modal>
359
+ )
360
+ );
361
+ }
362
+ }
363
+
364
+ export default compose(
365
+ injectIntl,
366
+ connect(
367
+ (state) => ({
368
+ request: state.content.subrequests?.[SUBREQUEST] || {},
369
+ types: filter(state.types.types, 'addable'),
370
+ }),
371
+ { createContent, getTypes },
372
+ ),
373
+ )(ContentsUploadModal);
@@ -94,4 +94,9 @@ defineMessages({
94
94
  id: 'form_limit',
95
95
  defaultMessage: 'Submission limit',
96
96
  },
97
+ modulistica_restraint: {
98
+ id: 'modulistica_restraint',
99
+ defaultMessage:
100
+ 'As per the official information architecture outlined in measure 1.4.1, all forms must be properly uploaded in the designated section within Amministrazione > Documenti e Dati > Modulistica, and linked to the relevant service sheet. It is no longer possible to upload files and attachments directly into this container.',
101
+ },
97
102
  });
@@ -152,6 +152,37 @@ iframe {
152
152
  font-weight: 700;
153
153
  }
154
154
  }
155
+ /*
156
+ Safari rendering issue workaround - B#60364
157
+ Safari rendering fix, icons and fonts coming late means shenanigans for Safari rendering, as
158
+ Safari is lazy and slow in loading fonts and icons dynamically.
159
+ Problem: Safari (tested on Safari 17.6) sometimes fails to calculate the layout correctly
160
+ when dealing with dynamic content such as lazy-loaded icons or fonts, combined with
161
+ `display: inline-block`. This can result in improperly positioned elements
162
+ until the page is re-rendered or refocused.
163
+
164
+ Solution: To fix this issue:
165
+ 1. Replace `display: inline-block` with `display: inline-flex`. This ensures Safari
166
+ handles the box model and inline context properly, especially when the element's
167
+ size or alignment depends on dynamic content.
168
+ 2. Add `position: relative;` to force a recalculation of layout, resolving rendering quirks.
169
+
170
+ Background: Safari's WebKit engine has known issues with `inline-block` combined
171
+ with delayed content rendering, such as lazy-loaded icons. Switching to `inline-flex`
172
+ better aligns with modern CSS rendering engines, while `position: relative;`
173
+ ensures the layout is recalculated.
174
+
175
+ References:
176
+ - CSS-Tricks: What Forces Layout or Reflow: https://css-tricks.com/what-forces-layout-reflow/
177
+ - WebKit Bug Reports on `inline-block` rendering issues with dynamic content.
178
+ - Testing and observations on Safari 17.6 behavior with lazy-loaded assets.
179
+ */
180
+ @supports (-webkit-appearance: none) {
181
+ a {
182
+ display: inline-flex; /* Evita problemi con inline-block */
183
+ position: relative; /* Forza Safari a calcolare il layout reflow correttamente */
184
+ }
185
+ }
155
186
  }
156
187
 
157
188
  div[class^='draftJsToolbar__toolbar__'] {
@@ -381,3 +412,13 @@ iframe {
381
412
  }
382
413
  }
383
414
  }
415
+
416
+ .public-ui
417
+ .it-header-slim-wrapper
418
+ .it-header-slim-wrapper-content
419
+ .it-header-slim-right-zone.header-slim-right-zone
420
+ .login-button {
421
+ @media (min-width: #{map-get($grid-breakpoints, md)}) and (max-width:#{map-get($grid-breakpoints, xl)}) {
422
+ flex: unset;
423
+ }
424
+ }