From e8be7d95e8ce05b2c12d3c5ba010f58b14e41ab3 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Mar 2024 17:09:57 +0100 Subject: [PATCH 01/10] feat: add EPFL logo w/ link to EPFL homepage --- web/frontend/src/assets/EPFL_Logo_184X53.svg | 21 ++++++++++++++++++++ web/frontend/src/layout/NavBar.tsx | 9 +++++++++ 2 files changed, 30 insertions(+) create mode 100644 web/frontend/src/assets/EPFL_Logo_184X53.svg diff --git a/web/frontend/src/assets/EPFL_Logo_184X53.svg b/web/frontend/src/assets/EPFL_Logo_184X53.svg new file mode 100644 index 000000000..f0f2074ae --- /dev/null +++ b/web/frontend/src/assets/EPFL_Logo_184X53.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/web/frontend/src/layout/NavBar.tsx b/web/frontend/src/layout/NavBar.tsx index 56ccf2fcf..336206a58 100644 --- a/web/frontend/src/layout/NavBar.tsx +++ b/web/frontend/src/layout/NavBar.tsx @@ -22,6 +22,7 @@ import { availableLanguages } from 'language/Configuration'; import { LanguageSelector } from '../language'; import logo from '../assets/logo.png'; +import { ReactComponent as EPFLLogo } from '../assets/EPFL_Logo_184X53.svg'; import { Popover, Transition } from '@headlessui/react'; import { LoginIcon, LogoutIcon, MenuIcon, XIcon } from '@heroicons/react/outline'; import { PlusIcon } from '@heroicons/react/solid'; @@ -177,6 +178,14 @@ const RightSideNavBar = ({ authCtx, handleLogout, handleChangeId, fctx, t }) => const LeftSideNavBar = ({ authCtx, t }) => (
+
+ + + +
Workflow From bb5ac076a8885a68db73b63de53b1e4ff1fd54e2 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Mar 2024 17:27:50 +0100 Subject: [PATCH 02/10] feat: use Arial font --- web/frontend/src/index.css | 5 ++--- web/frontend/src/layout/App.css | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/web/frontend/src/index.css b/web/frontend/src/index.css index 36ddaf597..f3b1f1a81 100644 --- a/web/frontend/src/index.css +++ b/web/frontend/src/index.css @@ -4,12 +4,11 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', - 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + font-family: Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; + font-family: Arial, monospace; } diff --git a/web/frontend/src/layout/App.css b/web/frontend/src/layout/App.css index 587fdfb4b..f2007544f 100644 --- a/web/frontend/src/layout/App.css +++ b/web/frontend/src/layout/App.css @@ -1,5 +1,5 @@ .App { - font-family: sans-serif; + font-family: Arial, sans-serif; color: rgb(71, 71, 71); background-color: white; position: relative; From 125f5398e82866a8f21e37e7d0df5c323e00d7c8 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Mar 2024 21:48:07 +0100 Subject: [PATCH 03/10] feat: change bg color to EPFL style --- .../src/components/modal/RedirectToModal.tsx | 2 +- web/frontend/src/layout/ClientError.tsx | 4 ++-- web/frontend/src/layout/Flash.tsx | 6 ++---- web/frontend/src/layout/NavBar.tsx | 6 +++--- web/frontend/src/layout/components/ChangeIdModal.tsx | 2 +- web/frontend/src/layout/components/Profile.tsx | 2 +- web/frontend/src/layout/components/WarningModal.tsx | 2 +- web/frontend/src/pages/Home.tsx | 2 +- web/frontend/src/pages/admin/AdminTable.tsx | 2 +- web/frontend/src/pages/admin/DKGTable.tsx | 2 +- .../src/pages/admin/components/AddAdminUserModal.tsx | 4 ++-- .../src/pages/admin/components/AddProxyModal.tsx | 2 +- .../src/pages/admin/components/EditProxyModal.tsx | 2 +- .../pages/admin/components/RemoveAdminUserModal.tsx | 2 +- .../src/pages/admin/components/RemoveProxyModal.tsx | 2 +- web/frontend/src/pages/ballot/Show.tsx | 2 +- .../src/pages/ballot/components/FormNotAvailable.tsx | 2 +- web/frontend/src/pages/form/Result.tsx | 8 ++++---- .../src/pages/form/components/AddQuestionModal.tsx | 2 +- .../src/pages/form/components/AddVotersModal.tsx | 8 ++++---- .../src/pages/form/components/ChooseProxyModal.tsx | 4 ++-- web/frontend/src/pages/form/components/FormForm.tsx | 2 +- .../src/pages/form/components/ProgressBar.tsx | 12 ++++++------ 23 files changed, 40 insertions(+), 42 deletions(-) diff --git a/web/frontend/src/components/modal/RedirectToModal.tsx b/web/frontend/src/components/modal/RedirectToModal.tsx index 29ab8b1f4..95d3151f0 100644 --- a/web/frontend/src/components/modal/RedirectToModal.tsx +++ b/web/frontend/src/components/modal/RedirectToModal.tsx @@ -73,7 +73,7 @@ const RedirectToModal: FC = ({
diff --git a/web/frontend/src/layout/ClientError.tsx b/web/frontend/src/layout/ClientError.tsx index 8040f9197..8a43e305a 100644 --- a/web/frontend/src/layout/ClientError.tsx +++ b/web/frontend/src/layout/ClientError.tsx @@ -35,7 +35,7 @@ export default function ClientError({ {statusCode === 401 && ( @@ -43,7 +43,7 @@ export default function ClientError({ {statusCode !== 401 && ( + className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-[#ff0000] hover:bg-[#b51f1f] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> {t('goHome')} )} diff --git a/web/frontend/src/layout/Flash.tsx b/web/frontend/src/layout/Flash.tsx index 91bd3fd04..41079ab05 100644 --- a/web/frontend/src/layout/Flash.tsx +++ b/web/frontend/src/layout/Flash.tsx @@ -17,7 +17,7 @@ const Flash = () => {
{ diff --git a/web/frontend/src/layout/components/Profile.tsx b/web/frontend/src/layout/components/Profile.tsx index 707c40582..7ff7b59c7 100644 --- a/web/frontend/src/layout/components/Profile.tsx +++ b/web/frontend/src/layout/components/Profile.tsx @@ -67,7 +67,7 @@ const Profile: FC = ({ ) : ( ); diff --git a/web/frontend/src/layout/components/WarningModal.tsx b/web/frontend/src/layout/components/WarningModal.tsx index 9b0257696..10fdf5bf2 100644 --- a/web/frontend/src/layout/components/WarningModal.tsx +++ b/web/frontend/src/layout/components/WarningModal.tsx @@ -26,7 +26,7 @@ const WarningModal: FC = ({ message, isShown, setIsShown, act
diff --git a/web/frontend/src/pages/Home.tsx b/web/frontend/src/pages/Home.tsx index 7e53675d2..223988264 100644 --- a/web/frontend/src/pages/Home.tsx +++ b/web/frontend/src/pages/Home.tsx @@ -33,7 +33,7 @@ const Home: FC = () => {
- diff --git a/web/frontend/src/pages/admin/AdminTable.tsx b/web/frontend/src/pages/admin/AdminTable.tsx index 925f16aed..3cd3f30c3 100644 --- a/web/frontend/src/pages/admin/AdminTable.tsx +++ b/web/frontend/src/pages/admin/AdminTable.tsx @@ -92,7 +92,7 @@ const AdminTable: FC = ({ users, setUsers }) => { diff --git a/web/frontend/src/pages/admin/DKGTable.tsx b/web/frontend/src/pages/admin/DKGTable.tsx index c6372ab02..7b47ec348 100644 --- a/web/frontend/src/pages/admin/DKGTable.tsx +++ b/web/frontend/src/pages/admin/DKGTable.tsx @@ -108,7 +108,7 @@ const DKGTable: FC = ({ nodeProxyAddresses, setNodeProxyAddresses diff --git a/web/frontend/src/pages/admin/components/AddAdminUserModal.tsx b/web/frontend/src/pages/admin/components/AddAdminUserModal.tsx index 0ad7eb773..717bc377c 100644 --- a/web/frontend/src/pages/admin/components/AddAdminUserModal.tsx +++ b/web/frontend/src/pages/admin/components/AddAdminUserModal.tsx @@ -107,7 +107,7 @@ const AddAdminUserModal: FC = ({ open, setOpen, handleAd key={personIdx} className={({ active }) => `relative cursor-default select-none py-2 pl-10 pr-4 ${ - active ? 'bg-indigo-100 text-indigo-900' : 'text-gray-900' + active ? 'bg-[#ff0000] text-indigo-900' : 'text-gray-900' }` } value={role}> @@ -137,7 +137,7 @@ const AddAdminUserModal: FC = ({ open, setOpen, handleAd const actionButton = ( @@ -153,7 +153,7 @@ export const AddVotersModal: FC = ({
-
+
@@ -171,7 +171,7 @@ export const AddVotersModal: FC = ({ diff --git a/web/frontend/src/pages/form/components/ChooseProxyModal.tsx b/web/frontend/src/pages/form/components/ChooseProxyModal.tsx index 3fe98adb4..c2d986d61 100644 --- a/web/frontend/src/pages/form/components/ChooseProxyModal.tsx +++ b/web/frontend/src/pages/form/components/ChooseProxyModal.tsx @@ -105,7 +105,7 @@ const ChooseProxyModal: FC = ({
-
+
= ({
diff --git a/web/frontend/src/pages/form/components/FormForm.tsx b/web/frontend/src/pages/form/components/FormForm.tsx index 2f74e04cf..514b03065 100644 --- a/web/frontend/src/pages/form/components/FormForm.tsx +++ b/web/frontend/src/pages/form/components/FormForm.tsx @@ -273,7 +273,7 @@ const FormForm: FC = () => {
diff --git a/web/frontend/src/index.tsx b/web/frontend/src/index.tsx index 112aee30a..dabfc523c 100644 --- a/web/frontend/src/index.tsx +++ b/web/frontend/src/index.tsx @@ -121,7 +121,7 @@ const Loading: FC = () => {
diff --git a/web/frontend/src/layout/ClientError.tsx b/web/frontend/src/layout/ClientError.tsx index 8a43e305a..fc4a150fe 100644 --- a/web/frontend/src/layout/ClientError.tsx +++ b/web/frontend/src/layout/ClientError.tsx @@ -20,7 +20,7 @@ export default function ClientError({
-

{statusCode}

+

{statusCode}

@@ -35,7 +35,7 @@ export default function ClientError({ {statusCode === 401 && ( @@ -43,7 +43,7 @@ export default function ClientError({ {statusCode !== 401 && ( + className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-[#ff0000] hover:bg-[#b51f1f] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#ff0000]"> {t('goHome')} )} diff --git a/web/frontend/src/layout/Flash.tsx b/web/frontend/src/layout/Flash.tsx index 41079ab05..18b0f9dad 100644 --- a/web/frontend/src/layout/Flash.tsx +++ b/web/frontend/src/layout/Flash.tsx @@ -33,7 +33,7 @@ const Flash = () => { diff --git a/web/frontend/src/layout/components/WarningModal.tsx b/web/frontend/src/layout/components/WarningModal.tsx index 10fdf5bf2..584b72df5 100644 --- a/web/frontend/src/layout/components/WarningModal.tsx +++ b/web/frontend/src/layout/components/WarningModal.tsx @@ -26,7 +26,7 @@ const WarningModal: FC = ({ message, isShown, setIsShown, act
diff --git a/web/frontend/src/pages/About.tsx b/web/frontend/src/pages/About.tsx index eb326e875..c12a78043 100644 --- a/web/frontend/src/pages/About.tsx +++ b/web/frontend/src/pages/About.tsx @@ -8,7 +8,7 @@ const About: FC = () => {
-

+

{t('aboutPlatform')}

@@ -30,7 +30,7 @@ const About: FC = () => {

diff --git a/web/frontend/src/pages/Home.tsx b/web/frontend/src/pages/Home.tsx index 223988264..4f9732327 100644 --- a/web/frontend/src/pages/Home.tsx +++ b/web/frontend/src/pages/Home.tsx @@ -15,10 +15,10 @@ const Home: FC = () => {
- + {t('homeWhatsNew')} - + {t('homeJustShippedVersion')} 1.0.0 @@ -33,7 +33,7 @@ const Home: FC = () => {
- diff --git a/web/frontend/src/pages/Loading.tsx b/web/frontend/src/pages/Loading.tsx index 7d7894b60..6212b9b16 100644 --- a/web/frontend/src/pages/Loading.tsx +++ b/web/frontend/src/pages/Loading.tsx @@ -8,7 +8,7 @@ const Loading: FC = () => {
diff --git a/web/frontend/src/pages/admin/AdminTable.tsx b/web/frontend/src/pages/admin/AdminTable.tsx index 3cd3f30c3..f1a43ed42 100644 --- a/web/frontend/src/pages/admin/AdminTable.tsx +++ b/web/frontend/src/pages/admin/AdminTable.tsx @@ -124,7 +124,7 @@ const AdminTable: FC = ({ users, setUsers }) => { {user.role}
handleDelete(user.sciper)}> {t('delete')}
diff --git a/web/frontend/src/pages/admin/ProxyRow.tsx b/web/frontend/src/pages/admin/ProxyRow.tsx index 152421203..455621ec2 100644 --- a/web/frontend/src/pages/admin/ProxyRow.tsx +++ b/web/frontend/src/pages/admin/ProxyRow.tsx @@ -36,7 +36,7 @@ const ProxyRow: FC = ({
-
@@ -46,7 +46,7 @@ const ProxyRow: FC = ({ {t('delete')}
-
diff --git a/web/frontend/src/pages/admin/components/AddAdminUserModal.tsx b/web/frontend/src/pages/admin/components/AddAdminUserModal.tsx index 717bc377c..0b47dee90 100644 --- a/web/frontend/src/pages/admin/components/AddAdminUserModal.tsx +++ b/web/frontend/src/pages/admin/components/AddAdminUserModal.tsx @@ -90,7 +90,7 @@ const AddAdminUserModal: FC = ({ open, setOpen, handleAd
- + {selectedRole} {selected ? ( - + ) : null} @@ -137,7 +137,7 @@ const AddAdminUserModal: FC = ({ open, setOpen, handleAd const actionButton = (
diff --git a/web/frontend/src/pages/ballot/components/FormNotAvailable.tsx b/web/frontend/src/pages/ballot/components/FormNotAvailable.tsx index cd339878b..6aae07581 100644 --- a/web/frontend/src/pages/ballot/components/FormNotAvailable.tsx +++ b/web/frontend/src/pages/ballot/components/FormNotAvailable.tsx @@ -22,7 +22,7 @@ export default function FormNotAvailable(props) {
+ className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-[#ff0000] hover:bg-[#b51f1f] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#ff0000]"> {t('returnToFormTable')}
diff --git a/web/frontend/src/pages/ballot/components/Select.tsx b/web/frontend/src/pages/ballot/components/Select.tsx index 211dbe019..5d7df8f6a 100644 --- a/web/frontend/src/pages/ballot/components/Select.tsx +++ b/web/frontend/src/pages/ballot/components/Select.tsx @@ -72,7 +72,7 @@ const Select: FC = ({ select, answers, setAnswers, language }) => {
= ({ rankResult, selectResult, textR diff --git a/web/frontend/src/pages/form/IndividualResult.tsx b/web/frontend/src/pages/form/IndividualResult.tsx index 8903a4255..376955ff6 100644 --- a/web/frontend/src/pages/form/IndividualResult.tsx +++ b/web/frontend/src/pages/form/IndividualResult.tsx @@ -281,7 +281,7 @@ const IndividualResult: FC = ({ diff --git a/web/frontend/src/pages/form/Result.tsx b/web/frontend/src/pages/form/Result.tsx index 747841891..8474c6fce 100644 --- a/web/frontend/src/pages/form/Result.tsx +++ b/web/frontend/src/pages/form/Result.tsx @@ -109,7 +109,7 @@ const FormResult: FC = () => { className={({ selected }) => selected ? 'w-full focus:ring-0 rounded-lg py-2.5 text-sm font-medium leading-5 text-white bg-[#ff0000] shadow' - : 'w-full focus:ring-0 rounded-lg py-2.5 text-sm font-medium leading-5 text-gray-700 hover:bg-[#ff0000] hover:text-indigo-500' + : 'w-full focus:ring-0 rounded-lg py-2.5 text-sm font-medium leading-5 text-gray-700 hover:bg-[#ff0000] hover:text-[#ff0000]' }> {t('resGroup')} @@ -118,7 +118,7 @@ const FormResult: FC = () => { className={({ selected }) => selected ? 'w-full focus:ring-0 rounded-lg py-2.5 text-sm font-medium leading-5 text-white bg-[#ff0000] shadow' - : 'w-full focus:ring-0 rounded-lg py-2.5 text-sm font-medium leading-5 text-gray-600 hover:bg-[#ff0000] hover:text-indigo-500' + : 'w-full focus:ring-0 rounded-lg py-2.5 text-sm font-medium leading-5 text-gray-600 hover:bg-[#ff0000] hover:text-[#ff0000]' }> {t('resIndiv')} diff --git a/web/frontend/src/pages/form/components/ActionButtons/ActionButton.tsx b/web/frontend/src/pages/form/components/ActionButtons/ActionButton.tsx index 2b5dc3b90..788820505 100644 --- a/web/frontend/src/pages/form/components/ActionButtons/ActionButton.tsx +++ b/web/frontend/src/pages/form/components/ActionButtons/ActionButton.tsx @@ -11,7 +11,7 @@ type ActionButtonProps = { const ActionButton: FC = ({ handleClick, ongoing, ongoingText, children }) => { return !ongoing ? ( diff --git a/web/frontend/src/pages/form/components/ActionButtons/ResultButton.tsx b/web/frontend/src/pages/form/components/ActionButtons/ResultButton.tsx index 5ccdccaeb..1db697621 100644 --- a/web/frontend/src/pages/form/components/ActionButtons/ResultButton.tsx +++ b/web/frontend/src/pages/form/components/ActionButtons/ResultButton.tsx @@ -8,7 +8,7 @@ const ResultButton = ({ status, formID }) => { return ( status === Status.ResultAvailable && ( -
+
diff --git a/web/frontend/src/pages/form/components/ActionButtons/VoteButton.tsx b/web/frontend/src/pages/form/components/ActionButtons/VoteButton.tsx index ce027a92f..781097db0 100644 --- a/web/frontend/src/pages/form/components/ActionButtons/VoteButton.tsx +++ b/web/frontend/src/pages/form/components/ActionButtons/VoteButton.tsx @@ -17,7 +17,7 @@ const VoteButton = ({ status, formID }) => { isLogged && ( @@ -154,7 +154,7 @@ export const AddVotersModal: FC = ({
-
@@ -171,13 +171,13 @@ export const AddVotersModal: FC = ({
diff --git a/web/frontend/src/pages/form/components/FormRow.tsx b/web/frontend/src/pages/form/components/FormRow.tsx index aaeb76ac9..a3bfc9ca1 100644 --- a/web/frontend/src/pages/form/components/FormRow.tsx +++ b/web/frontend/src/pages/form/components/FormRow.tsx @@ -28,7 +28,7 @@ const FormRow: FC = ({ form }) => { return ( - +
{formRowI18n.t('title', { ns: 'form', fallbackLng: 'en' })}
diff --git a/web/frontend/src/pages/form/components/FormTableFilter.tsx b/web/frontend/src/pages/form/components/FormTableFilter.tsx index 9a73afbeb..6b9ba0e02 100644 --- a/web/frontend/src/pages/form/components/FormTableFilter.tsx +++ b/web/frontend/src/pages/form/components/FormTableFilter.tsx @@ -144,7 +144,7 @@ const FormTableFilter: FC = ({ setStatusToKeep }) => { diff --git a/web/frontend/src/pages/form/components/IndigoSpinnerIcon.tsx b/web/frontend/src/pages/form/components/IndigoSpinnerIcon.tsx index b4f1cdecc..1ea90703e 100644 --- a/web/frontend/src/pages/form/components/IndigoSpinnerIcon.tsx +++ b/web/frontend/src/pages/form/components/IndigoSpinnerIcon.tsx @@ -1,7 +1,7 @@ const IndigoSpinnerIcon = () => { return ( diff --git a/web/frontend/src/pages/form/components/RemoveElementModal.tsx b/web/frontend/src/pages/form/components/RemoveElementModal.tsx index f4540abd7..ca33c6ff7 100644 --- a/web/frontend/src/pages/form/components/RemoveElementModal.tsx +++ b/web/frontend/src/pages/form/components/RemoveElementModal.tsx @@ -83,7 +83,7 @@ const RemoveElementModal: FC = ({
-
{displayChoices(result, index)}
+
{displayChoices(result, index)}
{prettifyChoice(select.ChoicesMap, index)}
diff --git a/web/frontend/src/pages/form/components/StatusTimeline.tsx b/web/frontend/src/pages/form/components/StatusTimeline.tsx index 350e3b55c..e6b9eb18a 100644 --- a/web/frontend/src/pages/form/components/StatusTimeline.tsx +++ b/web/frontend/src/pages/form/components/StatusTimeline.tsx @@ -53,8 +53,8 @@ const StatusTimeline: FC = ({ status, ongoingAction }) => { switch (state) { case 'complete': return ( -
- +
+ {t(step.name)}
@@ -62,9 +62,9 @@ const StatusTimeline: FC = ({ status, ongoingAction }) => { case 'current': return (
- + {t(step.name)}
@@ -73,9 +73,9 @@ const StatusTimeline: FC = ({ status, ongoingAction }) => { if (ongoingAction === index) { return (
- + {t(step.ongoing)}
diff --git a/web/frontend/src/pages/form/components/SubjectComponent.tsx b/web/frontend/src/pages/form/components/SubjectComponent.tsx index 7ae0f5355..afa6b8d01 100644 --- a/web/frontend/src/pages/form/components/SubjectComponent.tsx +++ b/web/frontend/src/pages/form/components/SubjectComponent.tsx @@ -365,7 +365,7 @@ const SubjectComponent: FC = ({
diff --git a/web/frontend/src/pages/form/components/Tabs.tsx b/web/frontend/src/pages/form/components/Tabs.tsx index 594160fe7..468b6de4a 100644 --- a/web/frontend/src/pages/form/components/Tabs.tsx +++ b/web/frontend/src/pages/form/components/Tabs.tsx @@ -20,7 +20,7 @@ const Tabs = ({ currentTab, setCurrentTab }) => { }} className={classNames( name === currentTab - ? 'border-indigo-500 text-indigo-600' + ? 'border-[#ff0000] text-[#ff0000]' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300', 'w-1/4 py-4 px-1 text-center border-b-2 font-medium text-sm' )} diff --git a/web/frontend/src/pages/form/components/UploadFile.tsx b/web/frontend/src/pages/form/components/UploadFile.tsx index 675a8e0f4..e60248645 100644 --- a/web/frontend/src/pages/form/components/UploadFile.tsx +++ b/web/frontend/src/pages/form/components/UploadFile.tsx @@ -55,7 +55,7 @@ const UploadFile = ({ updateForm, setShowModal, setTextModal }) => { onChange={(e) => handleDrop(e.target.files[0])} /> diff --git a/web/frontend/src/pages/form/components/utils/useChangeAction.tsx b/web/frontend/src/pages/form/components/utils/useChangeAction.tsx index e81ff4042..d2fd4c2c2 100644 --- a/web/frontend/src/pages/form/components/utils/useChangeAction.tsx +++ b/web/frontend/src/pages/form/components/utils/useChangeAction.tsx @@ -456,7 +456,7 @@ const useChangeAction = ( return (
{t('notLoggedInActionText1')} - {t('notLoggedInActionText3')} From 28118ec7ae3f03ed825184e2cafecfaef712321c Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Tue, 5 Mar 2024 10:45:41 +0100 Subject: [PATCH 05/10] feat: add URL to smart contract --- contracts/evoting/types/ballots.go | 7 +++-- contracts/evoting/types/ballots_test.go | 38 ++++++++++++------------- integration/performance_test.go | 6 ++-- internal/testing/fake/election.go | 17 +++++------ 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/contracts/evoting/types/ballots.go b/contracts/evoting/types/ballots.go index 11cc69b28..2d7d10932 100644 --- a/contracts/evoting/types/ballots.go +++ b/contracts/evoting/types/ballots.go @@ -255,9 +255,10 @@ func (b *Ballot) Equal(other Ballot) bool { // Title contains the titles in different languages. type Title struct { - En string - Fr string - De string + En string + Fr string + De string + URL string } // Hint contains explanations in different languages. diff --git a/contracts/evoting/types/ballots_test.go b/contracts/evoting/types/ballots_test.go index e280f513e..9b292f739 100644 --- a/contracts/evoting/types/ballots_test.go +++ b/contracts/evoting/types/ballots_test.go @@ -56,13 +56,13 @@ func TestBallot_Unmarshal(t *testing.T) { Selects: []Select{{ ID: decodedQuestionID(1), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 2, MinN: 2, Choices: make([]Choice, 3), }, { ID: decodedQuestionID(2), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 3, MinN: 3, Choices: make([]Choice, 5), @@ -70,7 +70,7 @@ func TestBallot_Unmarshal(t *testing.T) { Ranks: []Rank{{ ID: decodedQuestionID(3), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 4, MinN: 0, Choices: make([]Choice, 4), @@ -78,7 +78,7 @@ func TestBallot_Unmarshal(t *testing.T) { Texts: []Text{{ ID: decodedQuestionID(4), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 2, MinN: 2, MaxLength: 10, @@ -305,7 +305,7 @@ func TestSubject_MaxEncodedSize(t *testing.T) { subject := Subject{ Subjects: []Subject{{ ID: "", - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, Order: nil, Subjects: []Subject{}, Selects: []Select{}, @@ -315,13 +315,13 @@ func TestSubject_MaxEncodedSize(t *testing.T) { Selects: []Select{{ ID: encodedQuestionID(1), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 3, MinN: 0, Choices: make([]Choice, 3), }, { ID: encodedQuestionID(2), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 5, MinN: 0, Choices: make([]Choice, 5), @@ -329,7 +329,7 @@ func TestSubject_MaxEncodedSize(t *testing.T) { Ranks: []Rank{{ ID: encodedQuestionID(3), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 4, MinN: 0, Choices: make([]Choice, 4), @@ -337,7 +337,7 @@ func TestSubject_MaxEncodedSize(t *testing.T) { Texts: []Text{{ ID: encodedQuestionID(4), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 2, MinN: 0, MaxLength: 10, @@ -345,7 +345,7 @@ func TestSubject_MaxEncodedSize(t *testing.T) { Choices: make([]Choice, 2), }, { ID: encodedQuestionID(5), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 1, MinN: 0, MaxLength: 10, @@ -355,7 +355,7 @@ func TestSubject_MaxEncodedSize(t *testing.T) { } conf := Configuration{ - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, Scaffold: []Subject{subject}, } @@ -368,7 +368,7 @@ func TestSubject_MaxEncodedSize(t *testing.T) { func TestSubject_IsValid(t *testing.T) { mainSubject := &Subject{ ID: ID(base64.StdEncoding.EncodeToString([]byte("S1"))), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, Order: []ID{}, Subjects: []Subject{}, Selects: []Select{}, @@ -378,7 +378,7 @@ func TestSubject_IsValid(t *testing.T) { subSubject := &Subject{ ID: ID(base64.StdEncoding.EncodeToString([]byte("S2"))), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, Order: []ID{}, Subjects: []Subject{}, Selects: []Select{}, @@ -387,7 +387,7 @@ func TestSubject_IsValid(t *testing.T) { } configuration := Configuration{ - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, Scaffold: []Subject{*mainSubject, *subSubject}, } @@ -400,7 +400,7 @@ func TestSubject_IsValid(t *testing.T) { mainSubject.Selects = []Select{{ ID: encodedQuestionID(1), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 0, MinN: 0, Choices: make([]Choice, 0), @@ -408,7 +408,7 @@ func TestSubject_IsValid(t *testing.T) { mainSubject.Ranks = []Rank{{ ID: encodedQuestionID(1), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 0, MinN: 0, Choices: make([]Choice, 0), @@ -423,7 +423,7 @@ func TestSubject_IsValid(t *testing.T) { mainSubject.Ranks[0] = Rank{ ID: encodedQuestionID(2), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 0, MinN: 2, Choices: make([]Choice, 0), @@ -439,7 +439,7 @@ func TestSubject_IsValid(t *testing.T) { mainSubject.Ranks = []Rank{} mainSubject.Selects[0] = Select{ ID: encodedQuestionID(1), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 1, MinN: 0, Choices: make([]Choice, 0), @@ -455,7 +455,7 @@ func TestSubject_IsValid(t *testing.T) { mainSubject.Selects = []Select{} mainSubject.Texts = []Text{{ ID: encodedQuestionID(3), - Title: Title{En: "", Fr: "", De: ""}, + Title: Title{En: "", Fr: "", De: "", URL: ""}, MaxN: 2, MinN: 4, MaxLength: 0, diff --git a/integration/performance_test.go b/integration/performance_test.go index 6b46c46e6..c896fb839 100644 --- a/integration/performance_test.go +++ b/integration/performance_test.go @@ -77,7 +77,7 @@ func customVotesScenario(b *testing.B, stuffing bool) { fmt.Println("Creating form") // ##### CREATE FORM ##### - formID, err := createFormNChunks(m, types.Title{En: "Three votes form", Fr: "", De: ""}, adminID, numChunksPerBallot) + formID, err := createFormNChunks(m, types.Title{En: "Three votes form", Fr: "", De: "", URL: ""}, adminID, numChunksPerBallot) require.NoError(b, err) time.Sleep(time.Millisecond * 1000) @@ -198,14 +198,14 @@ func createFormNChunks(m txManager, title types.Title, admin string, numChunks i Scaffold: []types.Subject{ { ID: "aa", - Title: types.Title{En: "subject1", Fr: "", De: ""}, + Title: types.Title{En: "subject1", Fr: "", De: "", URL: ""}, Order: nil, Subjects: nil, Selects: nil, Ranks: []types.Rank{}, Texts: []types.Text{{ ID: "bb", - Title: types.Title{En: "Enter favorite snack", Fr: "", De: ""}, + Title: types.Title{En: "Enter favorite snack", Fr: "", De: "", URL: ""}, MaxN: 1, MinN: 0, MaxLength: uint(base64.StdEncoding.DecodedLen(textSize)), diff --git a/internal/testing/fake/election.go b/internal/testing/fake/election.go index 65902d306..489dae466 100644 --- a/internal/testing/fake/election.go +++ b/internal/testing/fake/election.go @@ -21,9 +21,10 @@ func NewForm(ctx serde.Context, snapshot store.Snapshot, formID string) (types.F form := types.Form{ Configuration: types.Configuration{ Title: types.Title{ - En: "dummyTitle", - Fr: "", - De: "", + En: "dummyTitle", + Fr: "", + De: "", + URL: "", }, }, FormID: formID, @@ -75,17 +76,17 @@ func NewKCPointsMarshalled(k int) ([]kyber.Point, []kyber.Point, kyber.Point) { // BasicConfiguration returns a basic form configuration var BasicConfiguration = types.Configuration{ - Title: types.Title{En: "formTitle", Fr: "", De: ""}, + Title: types.Title{En: "formTitle", Fr: "", De: "", URL: ""}, Scaffold: []types.Subject{ { ID: "aa", - Title: types.Title{En: "subject1", Fr: "", De: ""}, + Title: types.Title{En: "subject1", Fr: "", De: "", URL: ""}, Order: nil, Subjects: nil, Selects: []types.Select{ { ID: "bb", - Title: types.Title{En: "Select your favorite snacks", Fr: "", De: ""}, + Title: types.Title{En: "Select your favorite snacks", Fr: "", De: "", URL: ""}, MaxN: 3, MinN: 0, Choices: []types.Choice{{Choice: "snickers", URL: ""}, {Choice: "mars", URL: ""}, {Choice: "vodka", URL: ""}, {Choice: "babibel", URL: ""}}, @@ -96,7 +97,7 @@ var BasicConfiguration = types.Configuration{ }, { ID: "dd", - Title: types.Title{En: "subject2", Fr: "", De: ""}, + Title: types.Title{En: "subject2", Fr: "", De: "", URL: ""}, Order: nil, Subjects: nil, Selects: nil, @@ -104,7 +105,7 @@ var BasicConfiguration = types.Configuration{ Texts: []types.Text{ { ID: "ee", - Title: types.Title{En: "dissertation", Fr: "", De: ""}, + Title: types.Title{En: "dissertation", Fr: "", De: "", URL: ""}, MaxN: 1, MinN: 1, MaxLength: 3, From 15ab53154765bdd2ecfb8024e295f726ee90d0f8 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Tue, 5 Mar 2024 11:17:35 +0100 Subject: [PATCH 06/10] feat: add title URL to frontend --- .../src/components/utils/FillFormInfo.tsx | 2 +- web/frontend/src/mocks/mockData.ts | 30 +++++++++++++++---- .../pages/ballot/components/BallotDisplay.tsx | 6 ++-- .../src/pages/ballot/components/Rank.tsx | 4 +-- .../src/pages/ballot/components/Select.tsx | 4 +-- .../src/pages/ballot/components/Text.tsx | 4 +-- web/frontend/src/pages/form/GroupedResult.tsx | 12 ++++---- .../src/pages/form/IndividualResult.tsx | 14 ++++----- web/frontend/src/pages/form/Result.tsx | 7 +++-- .../form/components/AddQuestionModal.tsx | 8 +++++ .../src/pages/form/components/FormForm.tsx | 12 ++++++-- .../src/pages/form/components/FormRow.tsx | 2 +- .../src/pages/form/components/Question.tsx | 6 ++-- .../form/components/SubjectComponent.tsx | 12 ++++++++ .../pages/form/components/utils/display.tsx | 16 ++++------ .../src/pages/{utils.ts => utils.tsx} | 10 +++++++ .../src/schema/configurationValidation.ts | 1 + web/frontend/src/schema/form_conf.json | 15 ++++++---- web/frontend/src/types/configuration.ts | 1 + web/frontend/src/types/form.ts | 1 + web/frontend/src/types/getObjectType.ts | 5 ++++ 21 files changed, 120 insertions(+), 52 deletions(-) rename web/frontend/src/pages/{utils.ts => utils.tsx} (61%) diff --git a/web/frontend/src/components/utils/FillFormInfo.tsx b/web/frontend/src/components/utils/FillFormInfo.tsx index 75b99f93b..bfd7ea0b2 100644 --- a/web/frontend/src/components/utils/FillFormInfo.tsx +++ b/web/frontend/src/components/utils/FillFormInfo.tsx @@ -52,7 +52,7 @@ const useFillFormInfo = (formData: FormInfo) => { const useFillLightFormInfo = (formData: LightFormInfo) => { const [id, setId] = useState(''); - const [title, setTitle] = useState({ En: '', Fr: '', De: '' }); + const [title, setTitle] = useState<Title>({ En: '', Fr: '', De: '', URL: '' }); const [status, setStatus] = useState<Status>(null); const [pubKey, setPubKey] = useState<string>(''); diff --git a/web/frontend/src/mocks/mockData.ts b/web/frontend/src/mocks/mockData.ts index 6aa58feca..843aa1368 100644 --- a/web/frontend/src/mocks/mockData.ts +++ b/web/frontend/src/mocks/mockData.ts @@ -23,11 +23,11 @@ const mockRoster: string[] = [ ]; const mockForm1: any = { - Title: { En: 'Life on the campus', Fr: 'Vie sur le campus', De: 'Leben auf dem Campus' }, + Title: { En: 'Life on the campus', Fr: 'Vie sur le campus', De: 'Leben auf dem Campus', URL: '' }, Scaffold: [ { ID: (0xa2ab).toString(), - Title: { En: 'Rate the course', Fr: 'Note la course', De: 'Bewerten Sie den Kurs' }, + Title: { En: 'Rate the course', Fr: 'Note la course', De: 'Bewerten Sie den Kurs', URL: '' }, Order: [(0x3fb2).toString(), (0x41e2).toString(), (0xcd13).toString(), (0xff31).toString()], Subjects: [ { @@ -35,6 +35,7 @@ const mockForm1: any = { En: 'Let s talk about the food', Fr: 'Parlons de la nourriture', De: 'Sprechen wir über das Essen', + URL: '', }, ID: (0xff31).toString(), Order: [(0xa319).toString(), (0x19c7).toString()], @@ -46,6 +47,7 @@ const mockForm1: any = { En: 'Select your ingredients', Fr: 'Choisi tes ingrédients', De: 'Wählen Sie Ihre Zutaten aus', + URL: '', }, ID: (0xa319).toString(), MaxN: 2, @@ -64,6 +66,7 @@ const mockForm1: any = { En: 'Rank the cafeteria', Fr: 'Ordonne les cafet', De: 'Ordnen Sie die Mensen', + URL: '', }, ID: (0x19c7).toString(), MaxN: 3, @@ -85,6 +88,7 @@ const mockForm1: any = { En: 'How did you find the provided material, from 1 (bad) to 5 (excellent) ?', Fr: 'Comment trouves-tu le matériel fourni, de 1 (mauvais) à 5 (excellent) ?', De: 'Wie bewerten Sie das vorhandene Material, von 1 (schlecht) bis 5 (exzellent)?', + URL: '', }, ID: (0x3fb2).toString(), MaxN: 1, @@ -103,6 +107,7 @@ const mockForm1: any = { En: 'How did you find the teaching ?', Fr: 'Comment trouves-tu l enseignement ?', De: 'Wie fanden Sie den Unterricht?', + URL: '', }, ID: (0x41e2).toString(), MaxN: 1, @@ -125,6 +130,7 @@ const mockForm1: any = { En: 'Who were the two best TAs ?', Fr: 'Quels sont les deux meilleurs TA ?', De: 'Wer waren die beiden besten TutorInnen?', + URL: '', }, ID: (0xcd13).toString(), MaxLength: 20, @@ -173,11 +179,12 @@ const mockForm2: any = { En: 'Please give your opinion', Fr: 'Donne ton avis', De: 'Bitte sagen Sie Ihre Meinung', + URL: '', }, Scaffold: [ { ID: (0xa2ab).toString(), - Title: { En: 'Rate the course', Fr: 'Note le cours', De: 'Bewerten Sie den Kurs' }, + Title: { En: 'Rate the course', Fr: 'Note le cours', De: 'Bewerten Sie den Kurs', URL: '' }, Order: [(0x3fb2).toString(), (0xcd13).toString()], Selects: [ @@ -186,6 +193,7 @@ const mockForm2: any = { En: 'How did you find the provided material, from 1 (bad) to 5 (excellent) ?', Fr: 'Comment trouves-tu le matériel fourni, de 1 (mauvais) à 5 (excellent) ?', De: 'Wie bewerten Sie das vorhandene Material, von 1 (schlecht) zu 5 (exzellent)?', + URL: '', }, ID: (0x3fb2).toString(), MaxN: 1, @@ -206,6 +214,7 @@ const mockForm2: any = { En: 'Who were the two best TAs ?', Fr: 'Quels sont les deux meilleurs TA ?', De: 'Wer waren die beiden besten TutorInnen?', + URL: '', }, ID: (0xcd13).toString(), MaxLength: 40, @@ -225,7 +234,12 @@ const mockForm2: any = { }, { ID: (0x1234).toString(), - Title: { En: 'Tough choices', Fr: 'Choix difficiles', De: 'Schwierige Entscheidungen' }, + Title: { + En: 'Tough choices', + Fr: 'Choix difficiles', + De: 'Schwierige Entscheidungen', + URL: '', + }, Order: [(0xa319).toString(), (0xcafe).toString(), (0xbeef).toString()], Selects: [ { @@ -233,6 +247,7 @@ const mockForm2: any = { En: 'Select your ingredients', Fr: 'Choisis tes ingrédients', De: 'Wählen Sie Ihre Zutaten', + URL: '', }, ID: (0xa319).toString(), MaxN: 3, @@ -253,6 +268,7 @@ const mockForm2: any = { En: 'Which cafeteria serves the best coffee ?', Fr: 'Quelle cafétéria sert le meilleur café ?', De: 'Welches Café bietet den besten Kaffee an?', + URL: '', }, ID: (0xcafe).toString(), MaxN: 4, @@ -270,7 +286,7 @@ const mockForm2: any = { Hint: { En: '', Fr: '', De: '' }, }, { - Title: { En: 'IN or SC ?', Fr: 'IN ou SC ?', De: 'IN oder SC?' }, + Title: { En: 'IN or SC ?', Fr: 'IN ou SC ?', De: 'IN oder SC?', URL: '' }, ID: (0xbeef).toString(), MaxN: 2, MinN: 1, @@ -292,7 +308,7 @@ const mockForm2: any = { }; const mockForm3: any = { - Title: { En: 'Lunch', Fr: 'Déjeuner', De: 'Mittagessen' }, + Title: { En: 'Lunch', Fr: 'Déjeuner', De: 'Mittagessen', URL: '' }, Scaffold: [ { ID: '3cVHIxpx', @@ -300,6 +316,7 @@ const mockForm3: any = { En: 'Choose your lunch', Fr: 'Choisis ton déjeuner', De: 'Wählen Sie Ihr Mittagessen', + URL: '', }, Order: ['PGP'], Ranks: [], @@ -311,6 +328,7 @@ const mockForm3: any = { En: 'Select what you want', Fr: 'Choisis ce que tu veux', De: 'Wählen Sie aus was Sie wünschen', + URL: '', }, MaxN: 4, MinN: 0, diff --git a/web/frontend/src/pages/ballot/components/BallotDisplay.tsx b/web/frontend/src/pages/ballot/components/BallotDisplay.tsx index 50769a30b..e34a92a10 100644 --- a/web/frontend/src/pages/ballot/components/BallotDisplay.tsx +++ b/web/frontend/src/pages/ballot/components/BallotDisplay.tsx @@ -5,7 +5,7 @@ import Rank, { handleOnDragEnd } from './Rank'; import Select from './Select'; import Text from './Text'; import { DragDropContext } from 'react-beautiful-dnd'; -import { internationalize } from './../../utils'; +import { internationalize, urlizeLabel } from './../../utils'; type BallotDisplayProps = { configuration: Configuration; @@ -59,7 +59,7 @@ const BallotDisplay: FC<BallotDisplayProps> = ({ return ( <div key={subject.ID}> <h3 className="text-xl break-all pt-1 pb-1 sm:pt-2 sm:pb-2 border-t font-bold text-gray-600"> - {internationalize(language, subject.Title)} + {urlizeLabel(internationalize(language, subject.Title), subject.Title.URL)} </h3> {subject.Order.map((id: ID) => ( <div key={id}> @@ -80,7 +80,7 @@ const BallotDisplay: FC<BallotDisplayProps> = ({ <DragDropContext onDragEnd={(dropRes) => handleOnDragEnd(dropRes, answers, setAnswers)}> <div className="w-full mb-0 sm:mb-4 mt-4 sm:mt-6"> <h3 className="pb-6 break-all text-2xl text-center text-gray-700"> - {internationalize(language, titles)} + {urlizeLabel(internationalize(language, titles), titles.URL)} </h3> <div className="flex flex-col"> {configuration.Scaffold.map((subject: types.Subject) => SubjectTree(subject))} diff --git a/web/frontend/src/pages/ballot/components/Rank.tsx b/web/frontend/src/pages/ballot/components/Rank.tsx index 4091a67be..fe6684ce0 100644 --- a/web/frontend/src/pages/ballot/components/Rank.tsx +++ b/web/frontend/src/pages/ballot/components/Rank.tsx @@ -3,7 +3,7 @@ import { Draggable, DropResult, Droppable } from 'react-beautiful-dnd'; import { Answers, ID, RankQuestion } from 'types/configuration'; import { answersFrom } from 'types/getObjectType'; import HintButton from 'components/buttons/HintButton'; -import { internationalize } from './../../utils'; +import { internationalize, urlizeLabel } from './../../utils'; export const handleOnDragEnd = ( result: DropResult, @@ -95,7 +95,7 @@ const Rank: FC<RankProps> = ({ rank, answers, language }) => { <div className="grid grid-rows-1 grid-flow-col"> <div> <h3 className="text-lg break-words text-gray-600"> - {internationalize(language, titles)} + {urlizeLabel(internationalize(language, titles), titles.URL)} </h3> </div> <div className="text-right"> diff --git a/web/frontend/src/pages/ballot/components/Select.tsx b/web/frontend/src/pages/ballot/components/Select.tsx index 5d7df8f6a..ee630a4b1 100644 --- a/web/frontend/src/pages/ballot/components/Select.tsx +++ b/web/frontend/src/pages/ballot/components/Select.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { Answers, SelectQuestion } from 'types/configuration'; import { answersFrom } from 'types/getObjectType'; import HintButton from 'components/buttons/HintButton'; -import { internationalize } from './../../utils'; +import { internationalize, urlizeLabel } from './../../utils'; type SelectProps = { select: SelectQuestion; answers: Answers; @@ -89,7 +89,7 @@ const Select: FC<SelectProps> = ({ select, answers, setAnswers, language }) => { <div className="grid grid-rows-1 grid-flow-col"> <div> <h3 className="text-lg break-words text-gray-600"> - {internationalize(language, titles)} + {urlizeLabel(internationalize(language, titles), titles.URL)} </h3> </div> <div className="text-right"> diff --git a/web/frontend/src/pages/ballot/components/Text.tsx b/web/frontend/src/pages/ballot/components/Text.tsx index b76b472f6..7cb53dc1d 100644 --- a/web/frontend/src/pages/ballot/components/Text.tsx +++ b/web/frontend/src/pages/ballot/components/Text.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { Answers, TextQuestion } from 'types/configuration'; import { answersFrom } from 'types/getObjectType'; import HintButton from 'components/buttons/HintButton'; -import { internationalize } from './../../utils'; +import { internationalize, urlizeLabel } from './../../utils'; type TextProps = { text: TextQuestion; @@ -109,7 +109,7 @@ const Text: FC<TextProps> = ({ text, answers, setAnswers, language }) => { <div className="grid grid-rows-1 grid-flow-col"> <div> <h3 className="text-lg break-words text-gray-600 w-96"> - {internationalize(language, text.Title)} + {urlizeLabel(internationalize(language, text.Title), text.Title.URL)} </h3> </div> <div className="text-right"> diff --git a/web/frontend/src/pages/form/GroupedResult.tsx b/web/frontend/src/pages/form/GroupedResult.tsx index 5e2d727da..f477242a3 100644 --- a/web/frontend/src/pages/form/GroupedResult.tsx +++ b/web/frontend/src/pages/form/GroupedResult.tsx @@ -29,7 +29,7 @@ import { import { default as i18n } from 'i18next'; import SelectResult from './components/SelectResult'; import TextResult from './components/TextResult'; -import { internationalize } from './../utils'; +import { internationalize, urlizeLabel } from './../utils'; type GroupedResultProps = { rankResult: RankResults; @@ -82,7 +82,7 @@ const GroupedResult: FC<GroupedResultProps> = ({ rankResult, selectResult, textR return ( <div key={subject.ID}> <h2 className="text-xl pt-1 pb-1 sm:pt-2 sm:pb-2 border-t font-bold text-gray-600"> - {internationalize(i18n.language, subject.Title)} + {urlizeLabel(internationalize(i18n.language, subject.Title), subject.Title.URL)} </h2> {subject.Order.map((id: ID) => ( <div key={id}> @@ -100,7 +100,7 @@ const GroupedResult: FC<GroupedResultProps> = ({ rankResult, selectResult, textR }; const getResultData = (subject: Subject, dataToDownload: DownloadedResults[]) => { - dataToDownload.push({ Title: subject.Title.En }); + dataToDownload.push({ Title: subject.Title.En, URL: subject.Title.URL }); subject.Order.forEach((id: ID) => { const element = subject.Elements.get(id); @@ -116,7 +116,7 @@ const GroupedResult: FC<GroupedResultProps> = ({ rankResult, selectResult, textR return { Candidate: rank.Choices[index], Percentage: `${percent}%` }; } ); - dataToDownload.push({ Title: element.Title.En, Results: res }); + dataToDownload.push({ Title: element.Title.En, URL: element.Title.URL, Results: res }); } break; @@ -133,7 +133,7 @@ const GroupedResult: FC<GroupedResultProps> = ({ rankResult, selectResult, textR }; }) .sort((x, y) => y.TotalCount - x.TotalCount); - dataToDownload.push({ Title: element.Title.En, Results: res }); + dataToDownload.push({ Title: element.Title.En, URL: element.Title.URL, Results: res }); } break; @@ -146,7 +146,7 @@ const GroupedResult: FC<GroupedResultProps> = ({ rankResult, selectResult, textR res = Array.from(countTextResult(textResult.get(id)).resultsInPercent).map((r) => { return { Candidate: r[0], Percentage: `${r[1]}%` }; }); - dataToDownload.push({ Title: element.Title.En, Results: res }); + dataToDownload.push({ Title: element.Title.En, URL: element.Title.URL, Results: res }); } break; } diff --git a/web/frontend/src/pages/form/IndividualResult.tsx b/web/frontend/src/pages/form/IndividualResult.tsx index 376955ff6..01609e4b7 100644 --- a/web/frontend/src/pages/form/IndividualResult.tsx +++ b/web/frontend/src/pages/form/IndividualResult.tsx @@ -9,7 +9,7 @@ import { import { IndividualSelectResult } from './components/SelectResult'; import { IndividualTextResult } from './components/TextResult'; import { IndividualRankResult } from './components/RankResult'; -import { internationalize } from './../utils'; +import { internationalize, urlizeLabel } from './../utils'; import { useTranslation } from 'react-i18next'; import { ID, @@ -77,7 +77,7 @@ const IndividualResult: FC<IndividualResultProps> = ({ {questionIcons[element.Type]} </div> <h2 className="flex align-text-middle text-lg pb-2"> - {internationalize(i18n.language, element.Title)} + {urlizeLabel(internationalize(i18n.language, element.Title), element.Title.URL)} </h2> </div> {element.Type === RANK && rankResult.has(element.ID) && ( @@ -109,7 +109,7 @@ const IndividualResult: FC<IndividualResultProps> = ({ return ( <div key={subject.ID}> <h2 className="text-xl pt-1 pb-1 sm:pt-2 sm:pb-2 border-t font-bold text-gray-600"> - {internationalize(i18n.language, subject.Title)} + {urlizeLabel(internationalize(i18n.language, subject.Title), subject.Title.URL)} </h2> {subject.Order.map((id: ID) => ( <div key={id}> @@ -133,7 +133,7 @@ const IndividualResult: FC<IndividualResultProps> = ({ dataToDownload: DownloadedResults[], BallotID: number ) => { - dataToDownload.push({ Title: subject.Title.En }); + dataToDownload.push({ Title: subject.Title.En, URL: subject.Title.URL }); subject.Order.forEach((id: ID) => { const element = subject.Elements.get(id); @@ -150,7 +150,7 @@ const IndividualResult: FC<IndividualResultProps> = ({ Choice: rankQues.Choices[rankResult.get(id)[BallotID].indexOf(index)], }; }); - dataToDownload.push({ Title: element.Title.En, Results: res }); + dataToDownload.push({ Title: element.Title.En, URL: element.Title.URL, Results: res }); } break; @@ -162,7 +162,7 @@ const IndividualResult: FC<IndividualResultProps> = ({ const checked = select ? 'True' : 'False'; return { Candidate: selectQues.Choices[index], Checked: checked }; }); - dataToDownload.push({ Title: element.Title.En, Results: res }); + dataToDownload.push({ Title: element.Title.En, URL: element.Title.URL, Results: res }); } break; @@ -177,7 +177,7 @@ const IndividualResult: FC<IndividualResultProps> = ({ res = textResult.get(id)[BallotID].map((text, index) => { return { Field: textQues.Choices[index], Answer: text }; }); - dataToDownload.push({ Title: element.Title.En, Results: res }); + dataToDownload.push({ Title: element.Title.En, URL: element.Title.URL, Results: res }); } break; } diff --git a/web/frontend/src/pages/form/Result.tsx b/web/frontend/src/pages/form/Result.tsx index 8474c6fce..826c294e0 100644 --- a/web/frontend/src/pages/form/Result.tsx +++ b/web/frontend/src/pages/form/Result.tsx @@ -12,7 +12,7 @@ import { Tab } from '@headlessui/react'; import IndividualResult from './IndividualResult'; import { default as i18n } from 'i18next'; import GroupedResult from './GroupedResult'; -import { internationalize } from './../utils'; +import { internationalize, urlizeLabel } from './../utils'; // Functional component that displays the result of the votes const FormResult: FC = () => { @@ -98,7 +98,10 @@ const FormResult: FC = () => { {t('totalNumberOfVotes', { votes: result.length })} </h2> <h3 className="py-6 border-t text-2xl text-center text-gray-700"> - {internationalize(i18n.language, configuration.Title)} + {urlizeLabel( + internationalize(i18n.language, configuration.Title), + configuration.Title.URL + )} </h3> <div> diff --git a/web/frontend/src/pages/form/components/AddQuestionModal.tsx b/web/frontend/src/pages/form/components/AddQuestionModal.tsx index 3a3c24a33..480a888f7 100644 --- a/web/frontend/src/pages/form/components/AddQuestionModal.tsx +++ b/web/frontend/src/pages/form/components/AddQuestionModal.tsx @@ -221,6 +221,14 @@ const AddQuestionModal: FC<AddQuestionModalProps> = ({ className="my-1 px-1 w-60 ml-1 border rounded-md" /> )} + <input + value={Title.URL} + onChange={(e) => handleChange('Title')(e)} + name="QuestionTitleURL" + type="text" + placeholder={t('url')} + className="my-1 px-1 w-60 ml-1 border rounded-md" + /> </div> <div className="text-red-600"> {errors diff --git a/web/frontend/src/pages/form/components/FormForm.tsx b/web/frontend/src/pages/form/components/FormForm.tsx index 2454ca98e..5a91ebac1 100644 --- a/web/frontend/src/pages/form/components/FormForm.tsx +++ b/web/frontend/src/pages/form/components/FormForm.tsx @@ -8,7 +8,7 @@ import { CloudUploadIcon, PencilIcon, TrashIcon } from '@heroicons/react/solid'; import SubjectComponent from './SubjectComponent'; import UploadFile from './UploadFile'; import pollTransaction from './utils/TransactionPoll'; -import { internationalize } from './../../utils'; +import { internationalize, urlizeLabel } from './../../utils'; import configurationSchema from '../../../schema/configurationValidation'; import { Configuration, ID, Subject } from '../../../types/configuration'; @@ -221,6 +221,14 @@ const FormForm: FC<FormFormProps> = () => { className="m-3 px-1 w-100 text-lg border rounded-md" /> )} + <input + value={Title.URL} + onChange={(e) => setConf({ ...conf, Title: { ...Title, URL: e.target.value } })} + name="TitleURL" + type="text" + placeholder={t('url')} + className="m-3 px-1 w-100 text-lg border rounded-md" + /> <div className="ml-1"> <button className={`border p-1 rounded-md ${ @@ -237,7 +245,7 @@ const FormForm: FC<FormFormProps> = () => { <div className="mt-1 ml-3 w-[90%] break-words" onClick={() => setTitleChanging(true)}> - {internationalize(language, Title)} + {urlizeLabel(internationalize(language, Title), Title.URL)} </div> <div className="ml-1"> <button diff --git a/web/frontend/src/pages/form/components/FormRow.tsx b/web/frontend/src/pages/form/components/FormRow.tsx index a3bfc9ca1..973f1cb81 100644 --- a/web/frontend/src/pages/form/components/FormRow.tsx +++ b/web/frontend/src/pages/form/components/FormRow.tsx @@ -13,7 +13,7 @@ const FormRow: FC<FormRowProps> = ({ form }) => { const [titles, setTitles] = useState<any>({}); useEffect(() => { if (form.Title === undefined) return; - setTitles({ En: form.Title.En, Fr: form.Title.Fr, De: form.Title.De }); + setTitles({ En: form.Title.En, Fr: form.Title.Fr, De: form.Title.De, URL: form.Title.URL }); }, [form]); // let i18next handle choosing the appropriate language const formRowI18n = i18n.createInstance(); diff --git a/web/frontend/src/pages/form/components/Question.tsx b/web/frontend/src/pages/form/components/Question.tsx index c49ba1d64..3f4b90ace 100644 --- a/web/frontend/src/pages/form/components/Question.tsx +++ b/web/frontend/src/pages/form/components/Question.tsx @@ -7,7 +7,7 @@ import { RankQuestion, SelectQuestion, TextQuestion } from 'types/configuration' import SubjectDropdown from './SubjectDropdown'; import AddQuestionModal from './AddQuestionModal'; import DisplayTypeIcon from './DisplayTypeIcon'; -import { internationalize } from './../../utils'; +import { internationalize, urlizeLabel } from './../../utils'; type QuestionProps = { question: RankQuestion | SelectQuestion | TextQuestion; notifyParent(question: RankQuestion | SelectQuestion | TextQuestion): void; @@ -53,7 +53,9 @@ const Question: FC<QuestionProps> = ({ question, notifyParent, removeQuestion, l <div className="h-9 w-9 rounded-full bg-gray-100 mr-2 ml-1"> <DisplayTypeIcon Type={Type} /> </div> - <div className="pt-1.5 max-w-md pr-8 truncate">{internationalize(language, Title)}</div> + <div className="pt-1.5 max-w-md pr-8 truncate"> + {urlizeLabel(internationalize(language, Title), Title.URL)} + </div> </div> <div className="flex mt-2 ml-2"> diff --git a/web/frontend/src/pages/form/components/SubjectComponent.tsx b/web/frontend/src/pages/form/components/SubjectComponent.tsx index afa6b8d01..08e4a16b1 100644 --- a/web/frontend/src/pages/form/components/SubjectComponent.tsx +++ b/web/frontend/src/pages/form/components/SubjectComponent.tsx @@ -349,6 +349,18 @@ const SubjectComponent: FC<SubjectComponentProps> = ({ } `} /> )} + <input + value={Title.URL} + onChange={(e) => + setSubject({ ...subject, Title: { ...Title, URL: e.target.value } }) + } + name="SubjectTitleURL" + type="text" + placeholder={t('url')} + className={`m-3 px-1 w-120 border rounded-md ${ + nestedLevel === 0 ? 'text-lg' : 'text-md' + } `} + /> <div className="ml-1"> <button className={`border p-1 rounded-md ${Title.En.length === 0 && 'bg-gray-100'}`} diff --git a/web/frontend/src/pages/form/components/utils/display.tsx b/web/frontend/src/pages/form/components/utils/display.tsx index b84a6c3c5..11d94da02 100644 --- a/web/frontend/src/pages/form/components/utils/display.tsx +++ b/web/frontend/src/pages/form/components/utils/display.tsx @@ -1,17 +1,11 @@ import { default as i18n } from 'i18next'; +import { urlizeLabel } from './../../../utils'; export const prettifyChoice = (choicesMap, index) => { - const choice = ( - choicesMap.ChoicesMap.has(i18n.language) + return urlizeLabel( + (choicesMap.ChoicesMap.has(i18n.language) ? choicesMap.ChoicesMap.get(i18n.language) - : choicesMap.ChoicesMap.get('en') - )[index]; - const url = choicesMap.URLs[index]; - return url ? ( - <a href={url} style={{ color: 'blue', textDecoration: 'underline' }}> - {choice} - </a> - ) : ( - choice + : choicesMap.ChoicesMap.get('en'))[index], + choicesMap.URLs[index] ); }; diff --git a/web/frontend/src/pages/utils.ts b/web/frontend/src/pages/utils.tsx similarity index 61% rename from web/frontend/src/pages/utils.ts rename to web/frontend/src/pages/utils.tsx index faa5f3f9f..40b02dbbf 100644 --- a/web/frontend/src/pages/utils.ts +++ b/web/frontend/src/pages/utils.tsx @@ -10,3 +10,13 @@ export function internationalize(language: string, internationalizable: Hint | T return internationalizable.En; } } + +export const urlizeLabel = (label: string, url?: string) => { + return url ? ( + <a href={url} style={{ color: 'blue', textDecoration: 'underline' }}> + {label} + </a> + ) : ( + label + ); +}; diff --git a/web/frontend/src/schema/configurationValidation.ts b/web/frontend/src/schema/configurationValidation.ts index 81fabd359..1dc5d1c1a 100644 --- a/web/frontend/src/schema/configurationValidation.ts +++ b/web/frontend/src/schema/configurationValidation.ts @@ -5,6 +5,7 @@ const titleSchema = yup.object({ En: yup.string().required(), Fr: yup.string(), De: yup.string(), + URL: yup.string(), }); const hintSchema = yup.object({ En: yup.string(), diff --git a/web/frontend/src/schema/form_conf.json b/web/frontend/src/schema/form_conf.json index 3d1a2b8de..6f562cd43 100644 --- a/web/frontend/src/schema/form_conf.json +++ b/web/frontend/src/schema/form_conf.json @@ -7,7 +7,8 @@ "properties": { "En": { "type": "string" }, "Fr": { "type": "string" }, - "De": { "type": "string" } + "De": { "type": "string" }, + "URL": { "type": "string" } } }, "Scaffold": { @@ -21,7 +22,8 @@ "properties": { "En": { "type": "string" }, "Fr": { "type": "string" }, - "De": { "type": "string" } + "De": { "type": "string" }, + "URL": { "type": "string" } } }, "Order": { @@ -43,7 +45,8 @@ "properties": { "En": { "type": "string" }, "Fr": { "type": "string" }, - "De": { "type": "string" } + "De": { "type": "string" }, + "URL": { "type": "string" } } }, "MaxN": { "type": "number" }, @@ -82,7 +85,8 @@ "properties": { "En": { "type": "string" }, "Fr": { "type": "string" }, - "De": { "type": "string" } + "De": { "type": "string" }, + "URL": { "type": "string" } } }, "MaxN": { "type": "number" }, @@ -121,7 +125,8 @@ "properties": { "En": { "type": "string" }, "Fr": { "type": "string" }, - "De": { "type": "string" } + "De": { "type": "string" }, + "URL": { "type": "string" } } }, "MaxN": { "type": "number" }, diff --git a/web/frontend/src/types/configuration.ts b/web/frontend/src/types/configuration.ts index fc3944d28..27d8cbe47 100644 --- a/web/frontend/src/types/configuration.ts +++ b/web/frontend/src/types/configuration.ts @@ -10,6 +10,7 @@ interface Title { En: string; Fr: string; De: string; + URL: string; } // Hint diff --git a/web/frontend/src/types/form.ts b/web/frontend/src/types/form.ts index 71d5be18a..086ae2f75 100644 --- a/web/frontend/src/types/form.ts +++ b/web/frontend/src/types/form.ts @@ -80,6 +80,7 @@ type TextResults = Map<ID, string[][]>; interface DownloadedResults { Title: string; + URL: string; Results?: { Candidate: string; Percent?: string; diff --git a/web/frontend/src/types/getObjectType.ts b/web/frontend/src/types/getObjectType.ts index ba82902dc..bcbe3287f 100644 --- a/web/frontend/src/types/getObjectType.ts +++ b/web/frontend/src/types/getObjectType.ts @@ -10,6 +10,7 @@ const emptyConfiguration = (): types.Configuration => { En: '', Fr: '', De: '', + URL: '', }, Scaffold: [], }; @@ -22,6 +23,7 @@ const newSubject = (): types.Subject => { En: '', Fr: '', De: '', + URL: '', }, Order: [], Type: SUBJECT, @@ -36,6 +38,7 @@ const newRank = (): types.RankQuestion => { En: '', Fr: '', De: '', + URL: '', }, MaxN: 2, MinN: 2, @@ -57,6 +60,7 @@ const newSelect = (): types.SelectQuestion => { En: '', Fr: '', De: '', + URL: '', }, MaxN: 1, MinN: 1, @@ -78,6 +82,7 @@ const newText = (): types.TextQuestion => { En: '', Fr: '', De: '', + URL: '', }, MaxN: 1, MinN: 0, From 9b1fa5de2a54747ccc3e5de03f598f10a8401430 Mon Sep 17 00:00:00 2001 From: Carine Dengler <git@carine-dengler.de> Date: Tue, 5 Mar 2024 17:44:47 +0100 Subject: [PATCH 07/10] feat: use EPFL link style --- web/frontend/src/pages/ballot/components/Rank.tsx | 8 +------- web/frontend/src/pages/ballot/components/Select.tsx | 8 +------- web/frontend/src/pages/ballot/components/Text.tsx | 8 +------- web/frontend/src/pages/utils.tsx | 4 +++- 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/web/frontend/src/pages/ballot/components/Rank.tsx b/web/frontend/src/pages/ballot/components/Rank.tsx index fe6684ce0..4a779da8b 100644 --- a/web/frontend/src/pages/ballot/components/Rank.tsx +++ b/web/frontend/src/pages/ballot/components/Rank.tsx @@ -62,13 +62,7 @@ const Rank: FC<RankProps> = ({ rank, answers, language }) => { setTitles(rank.Title); }, [rank]); const choiceDisplay = (choice: string, url: string, rankIndex: number) => { - const prettyChoice = url ? ( - <a href={url} style={{ color: 'blue', textDecoration: 'underline' }}> - {choice} - </a> - ) : ( - choice - ); + const prettyChoice = urlizeLabel(choice, url); return ( <Draggable key={choice} draggableId={choice} index={rankIndex}> {(provided) => ( diff --git a/web/frontend/src/pages/ballot/components/Select.tsx b/web/frontend/src/pages/ballot/components/Select.tsx index ee630a4b1..eccdaf2ef 100644 --- a/web/frontend/src/pages/ballot/components/Select.tsx +++ b/web/frontend/src/pages/ballot/components/Select.tsx @@ -61,13 +61,7 @@ const Select: FC<SelectProps> = ({ select, answers, setAnswers, language }) => { }, [select]); const choiceDisplay = (isChecked: boolean, choice: string, url: string, choiceIndex: number) => { - const prettyChoice = url ? ( - <a href={url} style={{ color: 'blue', textDecoration: 'underline' }}> - {choice} - </a> - ) : ( - choice - ); + const prettyChoice = urlizeLabel(choice, url); return ( <div key={choice}> <input diff --git a/web/frontend/src/pages/ballot/components/Text.tsx b/web/frontend/src/pages/ballot/components/Text.tsx index 7cb53dc1d..eae4ccf9d 100644 --- a/web/frontend/src/pages/ballot/components/Text.tsx +++ b/web/frontend/src/pages/ballot/components/Text.tsx @@ -80,13 +80,7 @@ const Text: FC<TextProps> = ({ text, answers, setAnswers, language }) => { const choiceDisplay = (choice: string, url: string, choiceIndex: number) => { const columns = text.MaxLength > 50 ? 50 : text.MaxLength; - const prettyChoice = url ? ( - <a href={url} style={{ color: 'blue', textDecoration: 'underline' }}> - {choice} - </a> - ) : ( - choice - ); + const prettyChoice = urlizeLabel(choice, url); return ( <div className="flex mb-2 md:flex-row flex-col" key={choice}> <label htmlFor={choice} className="text-gray-600 mr-2 w-24 break-words text-md"> diff --git a/web/frontend/src/pages/utils.tsx b/web/frontend/src/pages/utils.tsx index 40b02dbbf..429c71961 100644 --- a/web/frontend/src/pages/utils.tsx +++ b/web/frontend/src/pages/utils.tsx @@ -13,7 +13,9 @@ export function internationalize(language: string, internationalizable: Hint | T export const urlizeLabel = (label: string, url?: string) => { return url ? ( - <a href={url} style={{ color: 'blue', textDecoration: 'underline' }}> + <a + href={url} + style={{ color: 'red', textDecoration: 'underline', textDecorationColor: 'white' }}> {label} </a> ) : ( From 0497f33e70522318855d1d97d9e75a31095a5825 Mon Sep 17 00:00:00 2001 From: Carine Dengler <git@carine-dengler.de> Date: Tue, 5 Mar 2024 17:48:26 +0100 Subject: [PATCH 08/10] fix: fix missing Title field when not 'en' language --- web/frontend/src/pages/form/components/FormForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/frontend/src/pages/form/components/FormForm.tsx b/web/frontend/src/pages/form/components/FormForm.tsx index 5a91ebac1..2ec618415 100644 --- a/web/frontend/src/pages/form/components/FormForm.tsx +++ b/web/frontend/src/pages/form/components/FormForm.tsx @@ -191,7 +191,7 @@ const FormForm: FC<FormFormProps> = () => { setLanguage={setLanguage} /> - {language === 'en' && ( + {(language === 'en' || !['en', 'fr', 'de'].includes(language)) && ( <input value={Title.En} onChange={(e) => setConf({ ...conf, Title: { ...Title, En: e.target.value } })} From 4ca033cd7cc012d5718e186305a127e0d3339e82 Mon Sep 17 00:00:00 2001 From: Carine Dengler <git@carine-dengler.de> Date: Tue, 5 Mar 2024 17:51:06 +0100 Subject: [PATCH 09/10] fix: fix missing title link --- web/frontend/src/pages/form/Show.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/frontend/src/pages/form/Show.tsx b/web/frontend/src/pages/form/Show.tsx index f11355635..08e6c207f 100644 --- a/web/frontend/src/pages/form/Show.tsx +++ b/web/frontend/src/pages/form/Show.tsx @@ -15,7 +15,7 @@ import useGetResults from './components/utils/useGetResults'; import UserIDTable from './components/UserIDTable'; import DKGStatusTable from './components/DKGStatusTable'; import LoadingButton from './components/LoadingButton'; -import { internationalize } from './../utils'; +import { internationalize, urlizeLabel } from './../utils'; import { default as i18n } from 'i18next'; const FormShow: FC = () => { @@ -223,7 +223,7 @@ const FormShow: FC = () => { {!loading ? ( <> <div className="pt-8 text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate"> - {internationalize(i18n.language, titles)} + {urlizeLabel(internationalize(i18n.language, titles), titles.URL)} </div> <div className="pt-2 break-all">Form ID : {formId}</div> From 56fbba5f0a10560c18d9aea6d4f58fc4c8957ea6 Mon Sep 17 00:00:00 2001 From: Carine Dengler <git@carine-dengler.de> Date: Tue, 5 Mar 2024 17:53:12 +0100 Subject: [PATCH 10/10] test: add EPFL logo test --- web/frontend/tests/navbar.spec.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/frontend/tests/navbar.spec.ts b/web/frontend/tests/navbar.spec.ts index 6226ff5e3..6190e9228 100644 --- a/web/frontend/tests/navbar.spec.ts +++ b/web/frontend/tests/navbar.spec.ts @@ -29,6 +29,12 @@ test('Assert D-Voting logo is present', async ({ page }) => { await expect(await logo.getByRole('link')).toHaveAttribute('href', '/'); }); +test('Assert EPFL logo is present', async ({ page }) => { + const logo = await page.getByTestId('leftSideNavBarEPFLLogo'); + await expect(logo).toBeVisible(); + await expect(await logo.getByRole('link')).toHaveAttribute('href', 'https://epfl.ch'); +}); + test('Assert link to form table is present', async ({ page }) => { const forms = await page.getByRole('link', { name: i18n.t('navBarStatus') }); await expect(forms).toBeVisible();