Skip to content

Commit ae3917c

Browse files
committed
Improve
1 parent 7ee26b1 commit ae3917c

26 files changed

Lines changed: 1368 additions & 210 deletions

apps/codebattle/assets/js/widgets/App.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,16 @@ export function TournamentPage() {
221221
}
222222

223223
export function GroupTournamentPage() {
224+
const container =
225+
document.getElementById("group-tournament-root") ||
226+
document.getElementById("group-tournament-admin-root");
227+
const tournamentId = container?.dataset?.groupTournamentId;
228+
224229
return (
225230
<Provider store={store}>
226231
<PersistGate loading={null} persistor={persistor}>
227232
<Suspense>
228-
<GroupTournament />
233+
<GroupTournament tournamentId={tournamentId} />
229234
</Suspense>
230235
</PersistGate>
231236
</Provider>

apps/codebattle/assets/js/widgets/middlewares/GroupTournament.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ const channel = new Channel();
1010
export const setTournamentChannel = (tournamentId) => {
1111
const newChannelName = `group_tournament:${tournamentId}`;
1212
return channel.setupChannel(newChannelName);
13-
}
13+
};
1414

1515
export const connectToTournament = () => (dispatch) => {
1616
if (!channel) {
17-
console.error('Channel not initialized');
17+
console.error("Channel not initialized");
1818
return;
1919
}
2020

@@ -35,48 +35,60 @@ export const connectToTournament = () => (dispatch) => {
3535
projectStatus,
3636
projectLink,
3737
invite,
38+
externalSetup,
3839
solutionEvolution,
3940
logs,
4041
code,
4142
langSlug,
4243
} = normalizedResponse;
4344

45+
console.log("group tournament join invite", invite);
46+
console.log("group tournament external setup", externalSetup);
47+
4448
dispatch(
4549
actions.setGroupTournamentData({
4650
status,
4751
projectStatus,
4852
projectLink,
4953
invite,
54+
externalSetup,
5055
solutionEvolution,
5156
logs,
5257
code,
5358
langSlug,
5459
}),
5560
);
56-
}
61+
};
5762

5863
channel.join().receive("ok", onJoinSuccess).receive("error", onJoinFailure);
5964

6065
return channel;
61-
}
66+
};
6267

6368
export const requestInviteUpdate = () => (dispatch) => {
6469
if (!channel) {
65-
console.error('Channel not initialized');
70+
console.error("Channel not initialized");
6671
return;
6772
}
6873

69-
channel.push(channelMethods.requestInviteUpdate, {})
70-
.receive('ok', (data) => {
71-
const invite = data;
74+
channel
75+
.push(channelMethods.requestInviteUpdate, {})
76+
.receive("ok", (data) => {
77+
const normalizedData = camelizeKeys(data);
78+
const invite = normalizedData.invite;
79+
const externalSetup = normalizedData.externalSetup;
7280

73-
dispatch(actions.updateInviteStatus(invite.state));
81+
dispatch(actions.updateInviteState(invite.state));
7482

7583
if (invite.inviteLink) {
7684
dispatch(actions.updateInviteLink(invite.inviteLink));
7785
}
86+
87+
if (externalSetup) {
88+
dispatch(actions.updateGroupTournamentData({ externalSetup }));
89+
}
7890
})
79-
.receive('error', (error) => {
80-
console.error('Request invite update failed', error);
91+
.receive("error", (error) => {
92+
console.error("Request invite update failed", error);
8193
});
8294
};

apps/codebattle/assets/js/widgets/pages/groupTournament/EvolutionPanel.jsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,20 @@ function EvolutionPanel({ items, tournamentStatus, setRunId }) {
88
</div>
99
<div className="card-body p-3 border-top">
1010
<div className="cb-overflow-y-auto max-vh-50">
11-
{tournamentStatus !== "finished" && (
12-
<a href="_blank">+ Add Solution</a>
13-
)}
11+
{tournamentStatus !== "finished" && <a href="_blank">+ Add Solution</a>}
1412
{items && items.length > 0 && (
1513
<div className="mt-2 small">
1614
<div className="list-group list-group-flush">
1715
{items.map((item, idx) => (
18-
<div
16+
<button
1917
key={idx}
18+
type="button"
2019
onClick={() => setRunId(item.id)}
21-
className="list-group-item px-0 py-1 border-0"
20+
className="list-group-item list-group-item-action px-0 py-1 border-0 text-left bg-transparent"
2221
>
2322
<span className="badge badge-secondary mr-2">v{idx + 1}</span>
2423
<span className="text-truncate">{item}</span>
25-
</div>
24+
</button>
2625
))}
2726
</div>
2827
</div>

apps/codebattle/assets/js/widgets/pages/groupTournament/GroupTournamentPage.jsx

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useMemo, useState } from "react";
1+
import React, { useEffect, useState } from "react";
22
import { useDispatch, useSelector } from "react-redux";
33

44
import Header from "./Header";
@@ -11,19 +11,20 @@ import * as selectors from "../../selectors";
1111
import Loading from "@/components/Loading";
1212
import { requestInviteUpdate } from "@/middlewares/GroupTournament";
1313

14-
function GroupTournamentPage() {
14+
function GroupTournamentPage({ tournamentId }) {
1515
const dispatch = useDispatch();
1616

1717
const [showInviteWindow, setShowInviteWindow] = useState(false);
1818
const [runId, setRunId] = useState();
1919

20-
useGroupTournamentChannel();
20+
useGroupTournamentChannel(tournamentId);
2121

2222
const {
2323
status,
2424
projectStatus,
2525
projectLink,
2626
invite,
27+
externalSetup,
2728
solutionEvolution,
2829
logs,
2930
code,
@@ -32,56 +33,60 @@ function GroupTournamentPage() {
3233

3334
const openExternalRegistrationWindow = () => {
3435
setShowInviteWindow(true);
35-
}
36+
};
3637

3738
const requestInviteUpdates = () => {
3839
requestInviteUpdate()(dispatch);
39-
}
40+
};
4041

4142
useEffect(() => {
4243
if (runId) {
4344
console.log(runId);
4445
}
45-
}, [runId])
46+
}, [runId]);
4647

4748
useEffect(() => {
4849
if (showInviteWindow) {
4950
open(invite.inviteLink, undefined, "left=100,top=100,width=960,height=640");
5051
}
51-
}, [showInviteWindow])
52+
}, [invite.inviteLink, showInviteWindow]);
5253

53-
if (invite.status === "loading") {
54+
if (invite.state === "loading") {
5455
return <Loading />;
5556
}
5657

57-
if (invite.status === "creating" || invite.status === "pending") {
58-
return <>
59-
<div className="container-fluid h-100">
60-
<div className="row justify-content-center h-100">
61-
<div className="col-lg-5 col-md-5 col-sm-5 px-md-4 align-content-center">
62-
<div className="card cb-card border cb-border-color cb-rounded shadow-sm p-5">
63-
<div className="d-flex">
64-
<button
65-
type="button"
66-
className="btn btn-success text-white cb-rounded w-100"
67-
onClick={openExternalRegistrationWindow}
68-
>
69-
Registration
70-
</button>
71-
<button
72-
type="button"
73-
className="btn btn-secondary cb-rounded w-100 ml-2"
74-
onClick={requestInviteUpdates}
75-
>
76-
Next Step
77-
</button>
58+
if (invite.state === "creating" || invite.state === "pending") {
59+
return (
60+
<>
61+
<div className="container-fluid h-100">
62+
<div className="row justify-content-center h-100">
63+
<div className="col-lg-5 col-md-5 col-sm-5 px-md-4 align-content-center">
64+
<div className="card cb-card border cb-border-color cb-rounded shadow-sm p-5">
65+
<div className="d-flex">
66+
<button
67+
type="button"
68+
className="btn btn-success text-white cb-rounded w-100"
69+
onClick={openExternalRegistrationWindow}
70+
>
71+
Registration
72+
</button>
73+
<button
74+
type="button"
75+
className="btn btn-secondary cb-rounded w-100 ml-2"
76+
onClick={requestInviteUpdates}
77+
>
78+
Next Step
79+
</button>
80+
</div>
81+
<small className="text-center mt-3">
82+
For this stage you need registrated on a new platform
83+
</small>
7884
</div>
79-
<small className="text-center mt-3">For this stage you need registrated on a new platform</small>
8085
</div>
8186
</div>
8287
</div>
83-
</div>
84-
</>
88+
</>
89+
);
8590
}
8691

8792
return (
@@ -94,10 +99,14 @@ function GroupTournamentPage() {
9499
</div>
95100
<div className="row mt-1">
96101
<div className="col-lg-3 col-md-3 col-12">
97-
<EvolutionPanel items={solutionEvolution} tournamentStatus={status} setRunId={setRunId} />
102+
<EvolutionPanel
103+
items={solutionEvolution}
104+
tournamentStatus={status}
105+
setRunId={setRunId}
106+
/>
98107
</div>
99108
<div className="col-lg-6 col-md-6 col-12">
100-
<MainPanel status={status} />
109+
<MainPanel status={status} externalSetup={externalSetup} />
101110
</div>
102111
<div className="col-lg-3 col-md-3 col-12">
103112
<EditorPanel text={code} lang={langSlug} />

apps/codebattle/assets/js/widgets/pages/groupTournament/MainPanel.jsx

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,52 @@
11
import React from "react";
22

3-
function MainPanel({ status }) {
3+
function MainPanel({ status, externalSetup }) {
44
return (
55
<div className="card border rounded">
66
<div className="card-header py-2">
77
<h6 className="mb-0">Tournament Overview</h6>
88
<small className="text-muted">Current status and controls</small>
99
</div>
1010
<div className="card-body p-3 border-top max-vh-50 overflow-auto">
11-
{/* MainPanel component placeholder */}
12-
<p className="text-muted mb-0">Main content area for tournament information and actions.</p>
11+
<p className="text-muted mb-3">Main content area for tournament information and actions.</p>
12+
{externalSetup ? (
13+
<div className="small">
14+
<div>
15+
<strong>External setup:</strong> {externalSetup.state}
16+
</div>
17+
<div>
18+
<strong>Repo:</strong> {externalSetup.repoState}
19+
</div>
20+
<div>
21+
<strong>Role:</strong> {externalSetup.roleState}
22+
</div>
23+
<div>
24+
<strong>Secret:</strong> {externalSetup.secretState}
25+
</div>
26+
<div>
27+
<strong>Repo slug:</strong> {externalSetup.repoSlug || "n/a"}
28+
</div>
29+
<div>
30+
<strong>Repo URL:</strong>{" "}
31+
{externalSetup.repoUrl ? (
32+
<a href={externalSetup.repoUrl} target="_blank" rel="noreferrer">
33+
{externalSetup.repoUrl}
34+
</a>
35+
) : (
36+
"n/a"
37+
)}
38+
</div>
39+
{externalSetup.lastError && Object.keys(externalSetup.lastError).length > 0 ? (
40+
<pre className="mt-2 mb-0 text-danger" style={{ whiteSpace: "pre-wrap" }}>
41+
{JSON.stringify(externalSetup.lastError, null, 2)}
42+
</pre>
43+
) : null}
44+
</div>
45+
) : (
46+
<div className="text-muted small">
47+
External setup is not required for this tournament.
48+
</div>
49+
)}
1350
</div>
1451
</div>
1552
);

apps/codebattle/assets/js/widgets/slices/groupTournament.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ const initialState = {
55
projectStatus: "loading", // "created" | "loading",
66
projectLink: null, // string | null
77
invite: {
8-
status: "pending", // "creating" | "pending" | "accepted" | "rejected" | "loading"
8+
state: "loading", // "creating" | "pending" | "accepted" | "failed" | "loading"
99
inviteLink: null,
1010
},
11+
externalSetup: null,
1112
solutionEvolution: [], // Array<{ id: string, status: "creating" | "finished" }>
1213
logs: [], // Array<object>
1314
code: "",
@@ -18,9 +19,13 @@ const groupTournament = createSlice({
1819
name: "groupTournament",
1920
initialState,
2021
reducers: {
21-
setGroupTournamentData: (_state, { payload }) => ({
22-
..._state
23-
// ...payload,
22+
setGroupTournamentData: (state, { payload }) => ({
23+
...state,
24+
...payload,
25+
invite: {
26+
...state.invite,
27+
...(payload.invite || {}),
28+
},
2429
}),
2530
updateGroupTournamentData: (state, { payload }) => ({
2631
...state,
@@ -29,8 +34,8 @@ const groupTournament = createSlice({
2934
updateGroupTournamentStatus: (state, { payload }) => {
3035
state.status = payload;
3136
},
32-
updateInviteStatus: (state, { payload }) => {
33-
state.invite.status = payload;
37+
updateInviteState: (state, { payload }) => {
38+
state.invite.state = payload;
3439
},
3540
updateInviteLink: (state, { payload }) => {
3641
state.invite.inviteLink = payload;
@@ -40,9 +45,9 @@ const groupTournament = createSlice({
4045
},
4146
updateSolutionEvolutionStatus: (state, { payload }) => {
4247
const { id, status } = payload;
43-
const item = state.solutionEvolution.find(item => item.id === id);
44-
if (item) {
45-
item.status = status;
48+
const solutionEvolutionItem = state.solutionEvolution.find((item) => item.id === id);
49+
if (solutionEvolutionItem) {
50+
solutionEvolutionItem.status = status;
4651
}
4752
},
4853
addLog: (state, { payload }) => {

apps/codebattle/assets/js/widgets/utils/useGroupTournamentChannel.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ const useGroupTournamentChannel = (tournamentId) => {
88
const dispatch = useDispatch();
99

1010
useEffect(() => {
11+
if (!tournamentId) {
12+
return undefined;
13+
}
14+
1115
const channel = TournamentActions.setTournamentChannel(tournamentId);
1216

1317
const clearTournamentChannel = () => {
@@ -20,7 +24,7 @@ const useGroupTournamentChannel = (tournamentId) => {
2024

2125
return clearTournamentChannel;
2226
// eslint-disable-next-line react-hooks/exhaustive-deps
23-
}, []);
27+
}, [dispatch, tournamentId]);
2428
};
2529

2630
export default useGroupTournamentChannel;

0 commit comments

Comments
 (0)