diff --git a/_layouts/software-details.html b/_layouts/software-details.html index 0c917142ec0d..caa3bc0af211 100644 --- a/_layouts/software-details.html +++ b/_layouts/software-details.html @@ -426,6 +426,13 @@

{{ page.publiccode.maintenance.type }}

+
+

+ Stato publiccode.yml + +

+

+ {% if page.publiccode.maintenance.type == "contract" %} {% if page.publiccode.maintenance.contractors[0].name != nil %}
diff --git a/assets/js/App.js b/assets/js/App.js index dd2f561ea50a..2e8b467436e3 100644 --- a/assets/js/App.js +++ b/assets/js/App.js @@ -2,6 +2,7 @@ import React, { useRef } from 'react'; import ReactDOM from 'react-dom'; import { SearchContainer } from './components/Search/SearchContainer.js'; import { CatalogueContainer } from './components/Catalogue/CatalogueContainer.js'; +import { PubliccodeBadge } from './components/PubliccodeBadge.js'; import { CatalogueItem } from './components/Catalogue/CatalogueItem.js'; import { MailingListSubscribe } from './components/MailingList/MailingListSubscribe.js'; import { MailingListConfirmation } from './components/MailingList/MailingListConfirmation.js'; @@ -9,6 +10,7 @@ import { MailingListConfirmation } from './components/MailingList/MailingListCon export const App = () => { const search = useRef(Array.from(document.getElementsByTagName('custom-search'))); const catalogue = useRef(Array.from(document.getElementsByTagName('custom-catalogue'))); + const publiccodeBadge = useRef(Array.from(document.getElementsByTagName('publiccode-badge'))); const thumbnails = useRef(Array.from(document.getElementsByTagName('catalogue-item'))); const mailingListSubscribe = useRef(Array.from(document.getElementsByTagName('mailing-list-subscribe'))); const mailingListConfirmation = useRef(Array.from(document.getElementsByTagName('mailing-list-confirmation'))); @@ -32,6 +34,7 @@ export const App = () => { {thumbnails.current.map((t) => renderThumbnail(t))} {mailingListSubscribe.current.map((p) => renderCustomElement(p, MailingListSubscribe))} {mailingListConfirmation.current.map((p) => renderCustomElement(p, MailingListConfirmation))} + {publiccodeBadge.current.map((p) => renderCustomElement(p, PubliccodeBadge))} ); }; diff --git a/assets/js/components/PubliccodeBadge.js b/assets/js/components/PubliccodeBadge.js new file mode 100644 index 000000000000..b3a22d8c9f9d --- /dev/null +++ b/assets/js/components/PubliccodeBadge.js @@ -0,0 +1,59 @@ +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; + +import { Spinner } from './Spinner'; + +const stateClass = { + loading: 'secondary', + good: 'success', + error: 'danger', +}; + +export const PubliccodeBadge = React.memo(({ id }) => { + const [publiccodeState, setPubliccodeState] = useState('loading'); + const logUrl = `https://api.developers.italia.it/v1/software/${id}/logs`; + + useEffect(() => { + async function fetchLogs() { + const res = await fetch(logUrl); + + if (res.status >= 200 || res.status <= 299) { + const data = await res.json(); + const good = data.data[0]?.message.includes('GOOD publiccode.yml'); + + setPubliccodeState(good ? 'good' : 'error'); + } else { + setPubliccodeState('error'); + } + } + + fetchLogs(); + }, [logUrl]); + + return ( + <> +
+ {publiccodeState === 'loading' && } + + {publiccodeState !== 'loading' && publiccodeState} + +
+ + + (log) + + + ); +}); + +PubliccodeBadge.propTypes = { + id: PropTypes.string.isRequired, +}; + +PubliccodeBadge.displayName = 'PubliccodeBadge'; diff --git a/assets/js/components/Spinner.css b/assets/js/components/Spinner.css new file mode 100644 index 000000000000..938da3d3515f --- /dev/null +++ b/assets/js/components/Spinner.css @@ -0,0 +1,56 @@ +.lds-ellipsis { + display: inline-block; + position: relative; + width: 80px; + height: 80px; + margin-bottom: 1rem; +} +.lds-ellipsis div { + position: absolute; + width: 6px; + height: 6px; + border-radius: 50%; + background: gray; + top: 0.5rem; + animation-timing-function: cubic-bezier(0, 1, 1, 0); +} +.lds-ellipsis div:nth-child(1) { + left: 8px; + animation: lds-ellipsis1 0.6s infinite; +} +.lds-ellipsis div:nth-child(2) { + left: 8px; + animation: lds-ellipsis2 0.6s infinite; +} +.lds-ellipsis div:nth-child(3) { + left: 32px; + animation: lds-ellipsis2 0.6s infinite; +} +.lds-ellipsis div:nth-child(4) { + left: 56px; + animation: lds-ellipsis3 0.6s infinite; +} +@keyframes lds-ellipsis1 { + 0% { + transform: scale(0); + } + 100% { + transform: scale(1); + } +} +@keyframes lds-ellipsis3 { + 0% { + transform: scale(1); + } + 100% { + transform: scale(0); + } +} +@keyframes lds-ellipsis2 { + 0% { + transform: translate(0, 0); + } + 100% { + transform: translate(24px, 0); + } +} diff --git a/assets/js/components/Spinner.js b/assets/js/components/Spinner.js new file mode 100644 index 000000000000..3c31df1e44e1 --- /dev/null +++ b/assets/js/components/Spinner.js @@ -0,0 +1,16 @@ +import React from 'react'; + +import './Spinner.css'; + +export const Spinner = React.memo(() => ( + <> +
+
+
+
+
+
+ +)); + +Spinner.displayName = 'Spinner';