Skip to content

Commit c42d630

Browse files
authored
Merge pull request #156 from dedis/front-fix-nodeToSetup
Fix empty proxy address in DKG setup request
2 parents 0dd318a + dbb1f2d commit c42d630

25 files changed

+384
-297
lines changed

web/frontend/src/components/utils/DKGStatus.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,21 @@ const DKGStatus: FC<DKGStatusProps> = ({ status }) => {
1313

1414
const DisplayStatus = () => {
1515
switch (status) {
16-
case NodeStatus.NotInitialized:
16+
case NodeStatus.Unreachable:
1717
return (
1818
<div className="flex items-center">
1919
<div>
2020
<MinusIcon className="ml-2 mr-2 h-5 w-5 text-gray-600" aria-hidden="true" />
2121
</div>
2222
</div>
2323
);
24+
case NodeStatus.NotInitialized:
25+
return (
26+
<div className="flex items-center">
27+
<div className="block h-4 w-4 bg-gray-500 rounded-full mr-2"></div>
28+
<div className="max-w-[16vw] truncate">{t('uninitialized')}</div>
29+
</div>
30+
);
2431
case NodeStatus.Initialized:
2532
return (
2633
<div className="flex items-center">
@@ -31,7 +38,7 @@ const DKGStatus: FC<DKGStatusProps> = ({ status }) => {
3138
case NodeStatus.Setup:
3239
return (
3340
<div className="flex items-center">
34-
<div className="block h-4 w-4 bg-green-500 rounded-full mr-2"></div>
41+
<div className="block h-4 w-4 bg-green-700 rounded-full mr-2"></div>
3542
<div>{t('statusSetup')}</div>
3643
</div>
3744
);

web/frontend/src/language/en.json

+10-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"next": "Next",
1515
"confirmDeleteUserSciper": "Do confirm deleting the role for the user sciper",
1616
"404Title": "Page not found",
17-
"403Title": "Unauthorized page",
17+
"403Title": "Forbidden page",
18+
"401Title": "Unauthorized page",
1819
"404Description": "The page you are looking for does not exist.",
1920
"403Description": "You are not authorized to access this page.",
2021
"goHome": "Go to home page",
@@ -56,6 +57,9 @@
5657
"homeJustShippedVersion": "Just shipped version",
5758
"homeText": "Use the navigation bar above to reach the page you want.",
5859
"loginText": "You need to login to access the content of {{from}}",
60+
"notLoggedInActionText1": "You need to ",
61+
"notLoggedInActionText2": "login",
62+
"notLoggedInActionText3": " to perform these actions.",
5963
"loginCallback": "We are proceeding with the authentication. You should be redirected...",
6064
"logout": "Logout",
6165
"namePlaceHolder": "Enter the name",
@@ -243,6 +247,10 @@
243247
"proxyUnreachable": "Timeout: the address of the proxy for the node ({{node}}) could not be resolved. ",
244248
"error": "Error: ",
245249
"actionLoading": "Action loading...",
246-
"statusLoading": "Status loading..."
250+
"statusLoading": "Status loading...",
251+
"actionNotAvailable": "Action not available",
252+
"uninitialized": "Uninitialized",
253+
"actionTextVoter1": "The election is not open yet, you can come back later to vote once it is open.",
254+
"actionTextVoter2": "The results of the election are not available yet."
247255
}
248256
}

web/frontend/src/layout/ClientError.tsx

+30-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1+
import { FlashContext } from 'index';
2+
import handleLogin from 'pages/session/HandleLogin';
3+
import { useContext } from 'react';
14
import { useTranslation } from 'react-i18next';
25
import { Link } from 'react-router-dom';
36
import { ROUTE_HOME } from 'Routes';
47

5-
export default function ClientError({ statusCode }: { statusCode: number }) {
8+
export default function ClientError({
9+
statusCode,
10+
description,
11+
}: {
12+
statusCode: number;
13+
description?: string;
14+
}) {
615
const { t } = useTranslation();
16+
const fctx = useContext(FlashContext);
717

818
return (
919
<div className="h-[calc(100vh-130px)]">
@@ -16,14 +26,27 @@ export default function ClientError({ statusCode }: { statusCode: number }) {
1626
<h1 className="text-4xl font-extrabold text-gray-900 tracking-tight sm:text-5xl">
1727
{t(`${statusCode}Title`)}
1828
</h1>
19-
<p className="mt-1 text-base text-gray-500">{t(`${statusCode}Description`)}</p>
29+
{description && <p className="mt-1 text-base text-gray-500">{description}</p>}
30+
{!description && (
31+
<p className="mt-1 text-base text-gray-500">{t(`${statusCode}Description`)}</p>
32+
)}
2033
</div>
2134
<div className="mt-10 flex space-x-3 sm:border-l sm:border-transparent sm:pl-6">
22-
<Link
23-
to={ROUTE_HOME}
24-
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
25-
{t('goHome')}
26-
</Link>
35+
{statusCode === 401 && (
36+
<button
37+
id="login-button"
38+
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
39+
onClick={() => handleLogin(fctx)}>
40+
{t('login')}
41+
</button>
42+
)}
43+
{statusCode !== 401 && (
44+
<Link
45+
to={ROUTE_HOME}
46+
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
47+
{t('goHome')}
48+
</Link>
49+
)}
2750
</div>
2851
</div>
2952
</main>

web/frontend/src/mocks/handlers.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const handlers = [
6363
? {
6464
lastname: 'Bobster',
6565
firstname: 'Alice',
66-
role: UserRole.Admin,
66+
role: UserRole.Voter,
6767
sciper: userId,
6868
}
6969
: {};
@@ -234,13 +234,18 @@ export const handlers = [
234234

235235
rest.post(endpoints.dkgActors, async (req, res, ctx) => {
236236
const body = req.body as NewDKGBody;
237-
const newDKGStatus = new Map(mockDKG.get(body.ElectionID));
238237

239-
mockElections.get(body.ElectionID).Roster.forEach((node) => {
240-
newDKGStatus.set(node, NodeStatus.Initialized);
238+
let node = '';
239+
mockElections.get(body.ElectionID).Roster.forEach((n) => {
240+
const p = mockNodeProxyAddresses.get(n);
241+
if (p === body.Proxy) {
242+
node = n;
243+
}
241244
});
242245

243246
setTimeout(() => {
247+
const newDKGStatus = new Map(mockDKG.get(body.ElectionID));
248+
newDKGStatus.set(node, NodeStatus.Initialized);
244249
mockDKG.set(body.ElectionID, newDKGStatus);
245250
}, INIT_TIMER);
246251

web/frontend/src/mocks/mockData.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ const mockNodes: string[] = [
1313
'123.456.78.9:9009',
1414
];
1515

16-
const mockRoster: string[] = ['123.456.78.9:9000', '123.456.78.9:9001', '123.456.78.9:9002'];
16+
const mockRoster: string[] = [
17+
'123.456.78.9:9000',
18+
'123.456.78.9:9001',
19+
'123.456.78.9:9002',
20+
'123.456.78.9:9003',
21+
'123.456.78.9:9004',
22+
'123.456.78.9:9005',
23+
];
1724

1825
const mockElection1: any = {
1926
MainTitle: 'Life on the campus',

web/frontend/src/pages/election/Show.tsx

+14-11
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,14 @@ const ElectionShow: FC = () => {
103103
}, [nodeToSetup]);
104104

105105
useEffect(() => {
106-
if (nodeProxyAddresses !== null && roster !== null) {
107-
if (nodeToSetup === null) {
108-
const node = roster[0];
109-
setNodeToSetup([node, nodeProxyAddresses.get(node)]);
106+
// Set default node to initialize
107+
if (status >= Status.Initialized) {
108+
const node = Array.from(nodeProxyAddresses).find(([_node, proxy]) => proxy !== '');
109+
if (node !== undefined) {
110+
setNodeToSetup(Array.from(nodeProxyAddresses).find(([_node, proxy]) => proxy !== ''));
110111
}
111112
}
112-
// eslint-disable-next-line react-hooks/exhaustive-deps
113-
}, [nodeProxyAddresses, nodeToSetup, roster]);
113+
}, [nodeProxyAddresses, status]);
114114

115115
useEffect(() => {
116116
if (roster !== null) {
@@ -139,20 +139,23 @@ const ElectionShow: FC = () => {
139139
if (DKGStatuses !== null && !DKGLoading) {
140140
const statuses = Array.from(DKGStatuses.values());
141141

142+
// TODO: can be modified such that if the majority of the node are
143+
// initialized than the election status can still be set to initialized
142144
if (statuses.includes(NodeStatus.NotInitialized)) return;
143145

144146
if (statuses.includes(NodeStatus.Setup)) {
145147
setStatus(Status.Setup);
146-
} else {
147-
setStatus(Status.Initialized);
148+
return;
148149
}
150+
151+
if (statuses.includes(NodeStatus.Unreachable)) return;
152+
153+
setStatus(Status.Initialized);
154+
149155
// Status Failed is handled by useChangeAction
150156
}
151157
}
152158

153-
if (status >= Status.Open) {
154-
setDKGLoading(false);
155-
}
156159
// eslint-disable-next-line react-hooks/exhaustive-deps
157160
}, [DKGStatuses, status, DKGLoading]);
158161

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { FC } from 'react';
2+
import IndigoSpinnerIcon from '../IndigoSpinnerIcon';
3+
4+
type ActionButtonProps = {
5+
handleClick: () => any;
6+
ongoing: boolean;
7+
ongoingText: string;
8+
children: JSX.Element;
9+
};
10+
11+
const ActionButton: FC<ActionButtonProps> = ({ handleClick, ongoing, ongoingText, children }) => {
12+
return !ongoing ? (
13+
<button onClick={handleClick}>
14+
<div className="whitespace-nowrap inline-flex items-center justify-center px-4 py-1 mr-2 border border-gray-300 text-sm rounded-full font-medium text-gray-700 hover:text-indigo-500">
15+
{children}
16+
</div>
17+
</button>
18+
) : (
19+
<div className="whitespace-nowrap inline-flex items-center justify-center px-4 py-1 mr-2 border border-gray-300 text-sm rounded-full font-medium text-gray-700">
20+
<IndigoSpinnerIcon />
21+
{ongoingText}
22+
</div>
23+
);
24+
};
25+
26+
export default ActionButton;

web/frontend/src/pages/election/components/ActionButtons/CancelButton.tsx

+10-15
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { AuthContext } from 'index';
33
import { useContext } from 'react';
44
import { useTranslation } from 'react-i18next';
55
import { OngoingAction, Status } from 'types/election';
6-
import IndigoSpinnerIcon from '../IndigoSpinnerIcon';
6+
import ActionButton from './ActionButton';
77

88
const CancelButton = ({ status, handleCancel, ongoingAction }) => {
99
const authCtx = useContext(AuthContext);
@@ -14,20 +14,15 @@ const CancelButton = ({ status, handleCancel, ongoingAction }) => {
1414
return (
1515
isAuthorized &&
1616
status === Status.Open && (
17-
<button onClick={handleCancel}>
18-
{ongoingAction !== OngoingAction.Canceling && (
19-
<div className="whitespace-nowrap inline-flex items-center justify-center px-4 py-1 mr-2 border border-gray-300 text-sm rounded-full font-medium text-gray-700 hover:text-indigo-500">
20-
<XIcon className="-ml-1 mr-2 h-5 w-5" aria-hidden="true" />
21-
{t('cancel')}
22-
</div>
23-
)}
24-
{ongoingAction === OngoingAction.Canceling && (
25-
<div className="whitespace-nowrap inline-flex items-center justify-center px-4 py-1 mr-2 border border-gray-300 text-sm rounded-full font-medium text-gray-700">
26-
<IndigoSpinnerIcon />
27-
{t('canceling')}
28-
</div>
29-
)}
30-
</button>
17+
<ActionButton
18+
handleClick={handleCancel}
19+
ongoing={ongoingAction === OngoingAction.Canceling}
20+
ongoingText={t('canceling')}>
21+
<>
22+
<XIcon className="-ml-1 mr-2 h-5 w-5" aria-hidden="true" />
23+
{t('cancel')}
24+
</>
25+
</ActionButton>
3126
)
3227
);
3328
};

web/frontend/src/pages/election/components/ActionButtons/CloseButton.tsx

+10-15
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useContext } from 'react';
44
import { useTranslation } from 'react-i18next';
55
import { OngoingAction, Status } from 'types/election';
66
import { UserRole } from 'types/userRole';
7-
import IndigoSpinnerIcon from '../IndigoSpinnerIcon';
7+
import ActionButton from './ActionButton';
88

99
const CloseButton = ({ status, handleClose, ongoingAction }) => {
1010
const authCtx = useContext(AuthContext);
@@ -15,20 +15,15 @@ const CloseButton = ({ status, handleClose, ongoingAction }) => {
1515
return (
1616
isAuthorized &&
1717
status === Status.Open && (
18-
<button onClick={handleClose}>
19-
{ongoingAction !== OngoingAction.Closing && (
20-
<div className="whitespace-nowrap inline-flex items-center justify-center px-4 py-1 mr-2 border border-gray-300 text-sm rounded-full font-medium text-gray-700 hover:text-indigo-500">
21-
<LockClosedIcon className="-ml-1 mr-2 h-5 w-" aria-hidden="true" />
22-
{t('close')}
23-
</div>
24-
)}
25-
{ongoingAction === OngoingAction.Closing && (
26-
<div className="whitespace-nowrap inline-flex items-center justify-center px-4 py-1 mr-2 border border-gray-300 text-sm rounded-full font-medium text-gray-700">
27-
<IndigoSpinnerIcon />
28-
{t('closing')}
29-
</div>
30-
)}
31-
</button>
18+
<ActionButton
19+
handleClick={handleClose}
20+
ongoing={ongoingAction === OngoingAction.Closing}
21+
ongoingText={t('closing')}>
22+
<>
23+
<LockClosedIcon className="-ml-1 mr-2 h-5 w-" aria-hidden="true" />
24+
{t('close')}
25+
</>
26+
</ActionButton>
3227
)
3328
);
3429
};

web/frontend/src/pages/election/components/ActionButtons/CombineButton.tsx

+10-17
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useContext } from 'react';
44
import { useTranslation } from 'react-i18next';
55
import { OngoingAction, Status } from 'types/election';
66
import { UserRole } from 'types/userRole';
7-
import IndigoSpinnerIcon from '../IndigoSpinnerIcon';
7+
import ActionButton from './ActionButton';
88

99
const CombineButton = ({ status, handleCombine, ongoingAction }) => {
1010
const authCtx = useContext(AuthContext);
@@ -15,22 +15,15 @@ const CombineButton = ({ status, handleCombine, ongoingAction }) => {
1515
return (
1616
isAuthorized &&
1717
status === Status.PubSharesSubmitted && (
18-
<span>
19-
<button onClick={handleCombine}>
20-
{ongoingAction === OngoingAction.None && (
21-
<div className="whitespace-nowrap inline-flex items-center justify-center px-4 py-1 mr-2 border border-gray-300 text-sm rounded-full font-medium text-gray-700 hover:text-indigo-500">
22-
<ShieldCheckIcon className="-ml-1 mr-2 h-5 w-5" aria-hidden="true" />
23-
{t('combine')}
24-
</div>
25-
)}
26-
{ongoingAction === OngoingAction.Combining && (
27-
<div className="whitespace-nowrap inline-flex items-center justify-center px-4 py-1 mr-2 border border-gray-300 text-sm rounded-full font-medium text-gray-700">
28-
<IndigoSpinnerIcon />
29-
{t('combining')}
30-
</div>
31-
)}
32-
</button>
33-
</span>
18+
<ActionButton
19+
handleClick={handleCombine}
20+
ongoing={ongoingAction === OngoingAction.Combining}
21+
ongoingText={t('combining')}>
22+
<>
23+
<ShieldCheckIcon className="-ml-1 mr-2 h-5 w-5" aria-hidden="true" />
24+
{t('combine')}
25+
</>
26+
</ActionButton>
3427
)
3528
);
3629
};

0 commit comments

Comments
 (0)