@capytale/meta-player 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc.json +4 -4
- package/LICENSE +674 -674
- package/README.md +12 -12
- package/eslint.config.js +28 -28
- package/index.html +15 -15
- package/package.json +60 -60
- package/public/themes/lara-dark-blue/theme.css +7015 -7015
- package/public/themes/lara-light-blue/theme.css +7005 -7005
- package/src/App.tsx +139 -139
- package/src/AppRedux.css +39 -39
- package/src/MetaPlayer.tsx +170 -170
- package/src/activityJs.ts +7 -7
- package/src/app/createAppSlice.ts +6 -6
- package/src/app/hooks.ts +12 -12
- package/src/app/store.ts +52 -52
- package/src/app.module.scss +80 -80
- package/src/demo.tsx +87 -87
- package/src/external/prime.ts +5 -5
- package/src/features/activityData/ExitWarning.ts +28 -28
- package/src/features/activityData/IsAntiCheatExitDetectionDisabledSetter.tsx +19 -19
- package/src/features/activityData/IsDirtySetter.tsx +17 -17
- package/src/features/activityData/MetaPlayerOptionsSetter.tsx +41 -41
- package/src/features/activityData/activityDataSlice.ts +256 -256
- package/src/features/activityData/activityJsData.ts +82 -82
- package/src/features/activityData/hooks.ts +34 -34
- package/src/features/activityData/metaPlayerOptions.ts +23 -23
- package/src/features/activityData/uiState.ts +20 -20
- package/src/features/activityJS/ActivityJSProvider.tsx +339 -339
- package/src/features/activityJS/AfterResetAction.tsx +23 -23
- package/src/features/activityJS/AfterSaveAction.tsx +23 -23
- package/src/features/activityJS/BeforeResetAction.tsx +23 -23
- package/src/features/activityJS/BeforeSaveAction.tsx +23 -23
- package/src/features/activityJS/Saver.tsx +167 -167
- package/src/features/activityJS/hooks.ts +85 -85
- package/src/features/activityJS/internal-hooks.ts +96 -96
- package/src/features/activityJS/saverSlice.ts +96 -96
- package/src/features/activitySettings/ActivitySettingsSetter.tsx +21 -21
- package/src/features/activitySettings/hooks.ts +12 -12
- package/src/features/activitySettings/index.tsx +43 -43
- package/src/features/activitySettings/store.ts +108 -108
- package/src/features/activitySettings/style.module.scss +8 -8
- package/src/features/activitySettings/types.ts +140 -140
- package/src/features/activitySettings/ui.tsx +299 -299
- package/src/features/functionalities/AttachedFilesFunctionality.ts +23 -23
- package/src/features/functionalities/PreviewDialog.tsx +83 -83
- package/src/features/functionalities/functionalitiesSlice.ts +98 -98
- package/src/features/functionalities/hooks.ts +70 -70
- package/src/features/layout/hooks.ts +7 -7
- package/src/features/layout/layoutSlice.ts +90 -90
- package/src/features/navbar/activity-info/index.tsx +54 -54
- package/src/features/navbar/activity-info/style.module.scss +38 -38
- package/src/features/navbar/activity-menu/ActivityQuickActions.tsx +57 -57
- package/src/features/navbar/activity-menu/index.tsx +154 -153
- package/src/features/navbar/activity-menu/style.module.scss +7 -7
- package/src/features/navbar/capytale-menu/CloneDialog.tsx +75 -75
- package/src/features/navbar/capytale-menu/Countdown.tsx +312 -312
- package/src/features/navbar/capytale-menu/CountdownAndSaveButton.tsx +115 -115
- package/src/features/navbar/capytale-menu/index.tsx +260 -260
- package/src/features/navbar/capytale-menu/style.module.scss +8 -8
- package/src/features/navbar/index.tsx +39 -39
- package/src/features/navbar/navbarSlice.ts +79 -79
- package/src/features/navbar/review-navbar/GradingNav.tsx +128 -128
- package/src/features/navbar/review-navbar/index.tsx +18 -18
- package/src/features/navbar/review-navbar/style.module.scss +22 -22
- package/src/features/navbar/sidebars/ActivitySidebarActions.tsx +57 -57
- package/src/features/navbar/sidebars/AttachedFilesSidebarContent.module.scss +43 -43
- package/src/features/navbar/sidebars/AttachedFilesSidebarContent.tsx +181 -181
- package/src/features/navbar/sidebars/SettingsSidebarContent.tsx +192 -192
- package/src/features/navbar/sidebars/style.module.scss +15 -15
- package/src/features/navbar/student-utils.ts +11 -11
- package/src/features/navbar/style.module.scss +65 -65
- package/src/features/pedago/InstructionsEditor.tsx +102 -102
- package/src/features/pedago/PdfEditor.tsx +91 -91
- package/src/features/pedago/PedagoCommands.tsx +353 -353
- package/src/features/pedago/SharedNotesEditor.tsx +144 -144
- package/src/features/pedago/index.tsx +207 -204
- package/src/features/pedago/style.module.scss +233 -233
- package/src/features/theming/ThemeSwitcher.tsx +51 -51
- package/src/features/theming/hooks.ts +6 -6
- package/src/features/theming/themingSlice.ts +93 -93
- package/src/features/toast.tsx +38 -38
- package/src/hooks/index.ts +16 -16
- package/src/index.css +132 -132
- package/src/index.ts +90 -90
- package/src/logo.svg +1 -1
- package/src/my_json_data.js +4146 -4146
- package/src/settings.ts +6 -6
- package/src/types.ts +9 -9
- package/src/utils/ButtonDoubleIcon.tsx +35 -35
- package/src/utils/CardSelector.tsx +41 -41
- package/src/utils/ErrorBoundary.tsx +41 -41
- package/src/utils/PopupButton.tsx +134 -134
- package/src/utils/activity.ts +8 -8
- package/src/utils/breakpoints.ts +4 -4
- package/src/utils/capytale.ts +10 -10
- package/src/utils/clipboard.ts +11 -11
- package/src/utils/download.ts +7 -7
- package/src/utils/equality.ts +32 -32
- package/src/utils/server-clock.ts +42 -42
- package/src/utils/style.module.scss +45 -45
- package/src/utils/useFullscreen.ts +65 -65
- package/src/vite-env.d.ts +1 -1
- package/tsconfig.json +28 -28
- package/tsconfig.node.json +9 -9
- package/vite.config.ts +11 -11
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
import type { PayloadAction } from "@reduxjs/toolkit";
|
|
2
|
-
import { createAppSlice } from "../../app/createAppSlice";
|
|
3
|
-
import { Callback, useFileUpload } from "use-file-upload";
|
|
4
|
-
export type QuickAction =
|
|
5
|
-
| {
|
|
6
|
-
type: "action";
|
|
7
|
-
title: string;
|
|
8
|
-
icon: string;
|
|
9
|
-
action: () => void;
|
|
10
|
-
}
|
|
11
|
-
| {
|
|
12
|
-
type: "file-upload";
|
|
13
|
-
accept?: string;
|
|
14
|
-
title: string;
|
|
15
|
-
icon: string;
|
|
16
|
-
action: (file: {
|
|
17
|
-
source: URL;
|
|
18
|
-
name: string;
|
|
19
|
-
size: number;
|
|
20
|
-
file: File;
|
|
21
|
-
}) => void;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export function usePerformQuickAction() {
|
|
25
|
-
const [_, selectFile] = useFileUpload();
|
|
26
|
-
return (action: QuickAction) => {
|
|
27
|
-
if (action.type === "action") {
|
|
28
|
-
action.action();
|
|
29
|
-
} else if (action.type === "file-upload") {
|
|
30
|
-
selectFile(
|
|
31
|
-
{ accept: action.accept, multiple: false },
|
|
32
|
-
action.action as Callback,
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface NavbarState {
|
|
39
|
-
quickActions: QuickAction[];
|
|
40
|
-
sidebarActions: QuickAction[];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const initialState: NavbarState = {
|
|
44
|
-
quickActions: [],
|
|
45
|
-
sidebarActions: [],
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// If you are not using async thunks you can use the standalone `createSlice`.
|
|
49
|
-
export const navbarSlice = createAppSlice({
|
|
50
|
-
name: "navbar",
|
|
51
|
-
// `createSlice` will infer the state type from the `initialState` argument
|
|
52
|
-
initialState,
|
|
53
|
-
// The `reducers` field lets us define reducers and generate associated actions
|
|
54
|
-
reducers: (create) => ({
|
|
55
|
-
setQuickActions: create.reducer(
|
|
56
|
-
(state, action: PayloadAction<QuickAction[]>) => {
|
|
57
|
-
state.quickActions = action.payload;
|
|
58
|
-
},
|
|
59
|
-
),
|
|
60
|
-
setSidebarActions: create.reducer(
|
|
61
|
-
(state, action: PayloadAction<QuickAction[]>) => {
|
|
62
|
-
state.sidebarActions = action.payload;
|
|
63
|
-
},
|
|
64
|
-
),
|
|
65
|
-
}),
|
|
66
|
-
// You can define your selectors here. These selectors receive the slice
|
|
67
|
-
// state as their first argument.
|
|
68
|
-
selectors: {
|
|
69
|
-
selectQuickActions: (navbar) => navbar.quickActions,
|
|
70
|
-
selectSidebarActions: (navbar) => navbar.sidebarActions,
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// Action creators are generated for each case reducer function.
|
|
75
|
-
export const { setQuickActions, setSidebarActions } = navbarSlice.actions;
|
|
76
|
-
|
|
77
|
-
// Selectors returned by `slice.selectors` take the root state as their first argument.
|
|
78
|
-
export const { selectQuickActions, selectSidebarActions } =
|
|
79
|
-
navbarSlice.selectors;
|
|
1
|
+
import type { PayloadAction } from "@reduxjs/toolkit";
|
|
2
|
+
import { createAppSlice } from "../../app/createAppSlice";
|
|
3
|
+
import { Callback, useFileUpload } from "use-file-upload";
|
|
4
|
+
export type QuickAction =
|
|
5
|
+
| {
|
|
6
|
+
type: "action";
|
|
7
|
+
title: string;
|
|
8
|
+
icon: string;
|
|
9
|
+
action: () => void;
|
|
10
|
+
}
|
|
11
|
+
| {
|
|
12
|
+
type: "file-upload";
|
|
13
|
+
accept?: string;
|
|
14
|
+
title: string;
|
|
15
|
+
icon: string;
|
|
16
|
+
action: (file: {
|
|
17
|
+
source: URL;
|
|
18
|
+
name: string;
|
|
19
|
+
size: number;
|
|
20
|
+
file: File;
|
|
21
|
+
}) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function usePerformQuickAction() {
|
|
25
|
+
const [_, selectFile] = useFileUpload();
|
|
26
|
+
return (action: QuickAction) => {
|
|
27
|
+
if (action.type === "action") {
|
|
28
|
+
action.action();
|
|
29
|
+
} else if (action.type === "file-upload") {
|
|
30
|
+
selectFile(
|
|
31
|
+
{ accept: action.accept, multiple: false },
|
|
32
|
+
action.action as Callback,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface NavbarState {
|
|
39
|
+
quickActions: QuickAction[];
|
|
40
|
+
sidebarActions: QuickAction[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const initialState: NavbarState = {
|
|
44
|
+
quickActions: [],
|
|
45
|
+
sidebarActions: [],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// If you are not using async thunks you can use the standalone `createSlice`.
|
|
49
|
+
export const navbarSlice = createAppSlice({
|
|
50
|
+
name: "navbar",
|
|
51
|
+
// `createSlice` will infer the state type from the `initialState` argument
|
|
52
|
+
initialState,
|
|
53
|
+
// The `reducers` field lets us define reducers and generate associated actions
|
|
54
|
+
reducers: (create) => ({
|
|
55
|
+
setQuickActions: create.reducer(
|
|
56
|
+
(state, action: PayloadAction<QuickAction[]>) => {
|
|
57
|
+
state.quickActions = action.payload;
|
|
58
|
+
},
|
|
59
|
+
),
|
|
60
|
+
setSidebarActions: create.reducer(
|
|
61
|
+
(state, action: PayloadAction<QuickAction[]>) => {
|
|
62
|
+
state.sidebarActions = action.payload;
|
|
63
|
+
},
|
|
64
|
+
),
|
|
65
|
+
}),
|
|
66
|
+
// You can define your selectors here. These selectors receive the slice
|
|
67
|
+
// state as their first argument.
|
|
68
|
+
selectors: {
|
|
69
|
+
selectQuickActions: (navbar) => navbar.quickActions,
|
|
70
|
+
selectSidebarActions: (navbar) => navbar.sidebarActions,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Action creators are generated for each case reducer function.
|
|
75
|
+
export const { setQuickActions, setSidebarActions } = navbarSlice.actions;
|
|
76
|
+
|
|
77
|
+
// Selectors returned by `slice.selectors` take the root state as their first argument.
|
|
78
|
+
export const { selectQuickActions, selectSidebarActions } =
|
|
79
|
+
navbarSlice.selectors;
|
|
@@ -1,128 +1,128 @@
|
|
|
1
|
-
import { useState, useEffect, useMemo, useCallback } from "react";
|
|
2
|
-
import evalApi from "@capytale/activity.js/backend/capytale/evaluation";
|
|
3
|
-
import { Dropdown } from "primereact/dropdown";
|
|
4
|
-
|
|
5
|
-
import { useAppSelector } from "../../../app/hooks";
|
|
6
|
-
import {
|
|
7
|
-
selectActivityInfo,
|
|
8
|
-
selectActivityNid,
|
|
9
|
-
selectMode,
|
|
10
|
-
selectNid,
|
|
11
|
-
} from "../../activityData/activityDataSlice";
|
|
12
|
-
import { studentNameFromInfo } from "../student-utils";
|
|
13
|
-
|
|
14
|
-
import { SaInfo } from "@capytale/activity.js/activity/evaluation/evaluation";
|
|
15
|
-
import { SelectItem, SelectItemOptionsType } from "primereact/selectitem";
|
|
16
|
-
import { Button } from "primereact/button";
|
|
17
|
-
|
|
18
|
-
const GradingNav: React.FC = () => {
|
|
19
|
-
const activityInfo = useAppSelector(selectActivityInfo);
|
|
20
|
-
const [studentList, setStudentList] = useState<SaInfo[]>([]);
|
|
21
|
-
const nid = useAppSelector(selectNid) as number;
|
|
22
|
-
const mode = useAppSelector(selectMode);
|
|
23
|
-
const activityNid = useAppSelector(selectActivityNid) as number;
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
evalApi.listSa(activityNid).then((j) => {
|
|
26
|
-
setStudentList(j);
|
|
27
|
-
});
|
|
28
|
-
}, []);
|
|
29
|
-
|
|
30
|
-
const goToStudent = useCallback(
|
|
31
|
-
(snid: string | number) => {
|
|
32
|
-
const redir = new URL(window.location.href);
|
|
33
|
-
redir.searchParams.set("id", snid.toString());
|
|
34
|
-
redir.searchParams.set("mode", mode);
|
|
35
|
-
location.href = redir.toString();
|
|
36
|
-
},
|
|
37
|
-
[mode],
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
const handlePrev = useCallback(() => {
|
|
41
|
-
if (studentList == null) return;
|
|
42
|
-
const i = studentList.findIndex((el) => (el.nid as number) == nid);
|
|
43
|
-
if (i <= 0) return;
|
|
44
|
-
goToStudent(studentList[i - 1].nid);
|
|
45
|
-
}, [studentList, nid, goToStudent]);
|
|
46
|
-
|
|
47
|
-
const handleNext = useCallback(() => {
|
|
48
|
-
if (studentList == null) return;
|
|
49
|
-
const i = studentList.findIndex((el) => el.nid == nid);
|
|
50
|
-
if (i < 0 || i >= studentList.length - 1) return;
|
|
51
|
-
goToStudent(studentList[i + 1].nid);
|
|
52
|
-
}, [studentList, nid, goToStudent]);
|
|
53
|
-
|
|
54
|
-
function getWf(el: SaInfo) {
|
|
55
|
-
if (el.workflow == "100") return { icon: "pi pi-pencil", color: "blue" };
|
|
56
|
-
if (el.workflow == "200")
|
|
57
|
-
return { icon: "pi pi-envelope", color: "orange" };
|
|
58
|
-
if (el.workflow == "300")
|
|
59
|
-
return { icon: "pi pi-list-check", color: "green" };
|
|
60
|
-
throw new Error("Unknown workflow");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const options: SelectItemOptionsType = useMemo(() => {
|
|
64
|
-
return studentList.map((el) => {
|
|
65
|
-
const item: SelectItem = {
|
|
66
|
-
label:
|
|
67
|
-
studentNameFromInfo({
|
|
68
|
-
firstName: el.firstname,
|
|
69
|
-
lastName: el.lastname,
|
|
70
|
-
class: el.classe,
|
|
71
|
-
}) || undefined,
|
|
72
|
-
value: el.nid,
|
|
73
|
-
icon: getWf(el).icon,
|
|
74
|
-
};
|
|
75
|
-
return item;
|
|
76
|
-
});
|
|
77
|
-
}, [studentList]);
|
|
78
|
-
|
|
79
|
-
if (studentList.length === 0) {
|
|
80
|
-
return <span>{studentNameFromInfo(activityInfo.studentInfo)}</span>;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const firstNid = studentList[0].nid as number;
|
|
84
|
-
const lastNid = studentList[Object.keys(studentList).length - 1]
|
|
85
|
-
.nid as number;
|
|
86
|
-
|
|
87
|
-
return (
|
|
88
|
-
<div className="p-inputgroup flex-1">
|
|
89
|
-
<Button
|
|
90
|
-
aria-label="Passer à la copie précédente"
|
|
91
|
-
size="small"
|
|
92
|
-
icon="pi pi-chevron-left"
|
|
93
|
-
severity="secondary"
|
|
94
|
-
onClick={handlePrev}
|
|
95
|
-
tooltip="Copie précédente"
|
|
96
|
-
tooltipOptions={{
|
|
97
|
-
position: "left",
|
|
98
|
-
}}
|
|
99
|
-
disabled={nid == firstNid}
|
|
100
|
-
outlined
|
|
101
|
-
/>
|
|
102
|
-
<Dropdown
|
|
103
|
-
aria-label="Sélectionner une copie"
|
|
104
|
-
value={nid}
|
|
105
|
-
options={options}
|
|
106
|
-
filter
|
|
107
|
-
onChange={(e) => {
|
|
108
|
-
goToStudent(e.value);
|
|
109
|
-
}}
|
|
110
|
-
/>
|
|
111
|
-
<Button
|
|
112
|
-
aria-label="Passer à la copie suivante"
|
|
113
|
-
size="small"
|
|
114
|
-
icon="pi pi-chevron-right"
|
|
115
|
-
severity="secondary"
|
|
116
|
-
onClick={handleNext}
|
|
117
|
-
tooltip="Copie suivante"
|
|
118
|
-
tooltipOptions={{
|
|
119
|
-
position: "right",
|
|
120
|
-
}}
|
|
121
|
-
disabled={nid == lastNid}
|
|
122
|
-
outlined
|
|
123
|
-
/>
|
|
124
|
-
</div>
|
|
125
|
-
);
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
export default GradingNav;
|
|
1
|
+
import { useState, useEffect, useMemo, useCallback } from "react";
|
|
2
|
+
import evalApi from "@capytale/activity.js/backend/capytale/evaluation";
|
|
3
|
+
import { Dropdown } from "primereact/dropdown";
|
|
4
|
+
|
|
5
|
+
import { useAppSelector } from "../../../app/hooks";
|
|
6
|
+
import {
|
|
7
|
+
selectActivityInfo,
|
|
8
|
+
selectActivityNid,
|
|
9
|
+
selectMode,
|
|
10
|
+
selectNid,
|
|
11
|
+
} from "../../activityData/activityDataSlice";
|
|
12
|
+
import { studentNameFromInfo } from "../student-utils";
|
|
13
|
+
|
|
14
|
+
import { SaInfo } from "@capytale/activity.js/activity/evaluation/evaluation";
|
|
15
|
+
import { SelectItem, SelectItemOptionsType } from "primereact/selectitem";
|
|
16
|
+
import { Button } from "primereact/button";
|
|
17
|
+
|
|
18
|
+
const GradingNav: React.FC = () => {
|
|
19
|
+
const activityInfo = useAppSelector(selectActivityInfo);
|
|
20
|
+
const [studentList, setStudentList] = useState<SaInfo[]>([]);
|
|
21
|
+
const nid = useAppSelector(selectNid) as number;
|
|
22
|
+
const mode = useAppSelector(selectMode);
|
|
23
|
+
const activityNid = useAppSelector(selectActivityNid) as number;
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
evalApi.listSa(activityNid).then((j) => {
|
|
26
|
+
setStudentList(j);
|
|
27
|
+
});
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
const goToStudent = useCallback(
|
|
31
|
+
(snid: string | number) => {
|
|
32
|
+
const redir = new URL(window.location.href);
|
|
33
|
+
redir.searchParams.set("id", snid.toString());
|
|
34
|
+
redir.searchParams.set("mode", mode);
|
|
35
|
+
location.href = redir.toString();
|
|
36
|
+
},
|
|
37
|
+
[mode],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const handlePrev = useCallback(() => {
|
|
41
|
+
if (studentList == null) return;
|
|
42
|
+
const i = studentList.findIndex((el) => (el.nid as number) == nid);
|
|
43
|
+
if (i <= 0) return;
|
|
44
|
+
goToStudent(studentList[i - 1].nid);
|
|
45
|
+
}, [studentList, nid, goToStudent]);
|
|
46
|
+
|
|
47
|
+
const handleNext = useCallback(() => {
|
|
48
|
+
if (studentList == null) return;
|
|
49
|
+
const i = studentList.findIndex((el) => el.nid == nid);
|
|
50
|
+
if (i < 0 || i >= studentList.length - 1) return;
|
|
51
|
+
goToStudent(studentList[i + 1].nid);
|
|
52
|
+
}, [studentList, nid, goToStudent]);
|
|
53
|
+
|
|
54
|
+
function getWf(el: SaInfo) {
|
|
55
|
+
if (el.workflow == "100") return { icon: "pi pi-pencil", color: "blue" };
|
|
56
|
+
if (el.workflow == "200")
|
|
57
|
+
return { icon: "pi pi-envelope", color: "orange" };
|
|
58
|
+
if (el.workflow == "300")
|
|
59
|
+
return { icon: "pi pi-list-check", color: "green" };
|
|
60
|
+
throw new Error("Unknown workflow");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const options: SelectItemOptionsType = useMemo(() => {
|
|
64
|
+
return studentList.map((el) => {
|
|
65
|
+
const item: SelectItem = {
|
|
66
|
+
label:
|
|
67
|
+
studentNameFromInfo({
|
|
68
|
+
firstName: el.firstname,
|
|
69
|
+
lastName: el.lastname,
|
|
70
|
+
class: el.classe,
|
|
71
|
+
}) || undefined,
|
|
72
|
+
value: el.nid,
|
|
73
|
+
icon: getWf(el).icon,
|
|
74
|
+
};
|
|
75
|
+
return item;
|
|
76
|
+
});
|
|
77
|
+
}, [studentList]);
|
|
78
|
+
|
|
79
|
+
if (studentList.length === 0) {
|
|
80
|
+
return <span>{studentNameFromInfo(activityInfo.studentInfo)}</span>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const firstNid = studentList[0].nid as number;
|
|
84
|
+
const lastNid = studentList[Object.keys(studentList).length - 1]
|
|
85
|
+
.nid as number;
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<div className="p-inputgroup flex-1">
|
|
89
|
+
<Button
|
|
90
|
+
aria-label="Passer à la copie précédente"
|
|
91
|
+
size="small"
|
|
92
|
+
icon="pi pi-chevron-left"
|
|
93
|
+
severity="secondary"
|
|
94
|
+
onClick={handlePrev}
|
|
95
|
+
tooltip="Copie précédente"
|
|
96
|
+
tooltipOptions={{
|
|
97
|
+
position: "left",
|
|
98
|
+
}}
|
|
99
|
+
disabled={nid == firstNid}
|
|
100
|
+
outlined
|
|
101
|
+
/>
|
|
102
|
+
<Dropdown
|
|
103
|
+
aria-label="Sélectionner une copie"
|
|
104
|
+
value={nid}
|
|
105
|
+
options={options}
|
|
106
|
+
filter
|
|
107
|
+
onChange={(e) => {
|
|
108
|
+
goToStudent(e.value);
|
|
109
|
+
}}
|
|
110
|
+
/>
|
|
111
|
+
<Button
|
|
112
|
+
aria-label="Passer à la copie suivante"
|
|
113
|
+
size="small"
|
|
114
|
+
icon="pi pi-chevron-right"
|
|
115
|
+
severity="secondary"
|
|
116
|
+
onClick={handleNext}
|
|
117
|
+
tooltip="Copie suivante"
|
|
118
|
+
tooltipOptions={{
|
|
119
|
+
position: "right",
|
|
120
|
+
}}
|
|
121
|
+
disabled={nid == lastNid}
|
|
122
|
+
outlined
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export default GradingNav;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { FC } from "react";
|
|
2
|
-
import GradingNav from "./GradingNav";
|
|
3
|
-
|
|
4
|
-
import styles from "./style.module.scss";
|
|
5
|
-
|
|
6
|
-
const ReviewNavbar: FC = () => {
|
|
7
|
-
return (
|
|
8
|
-
<div className={styles.reviewNavbar}>
|
|
9
|
-
<div aria-label="Indicateur de mode correction">Mode correction</div>
|
|
10
|
-
<div>
|
|
11
|
-
<GradingNav />
|
|
12
|
-
</div>
|
|
13
|
-
<div></div>
|
|
14
|
-
</div>
|
|
15
|
-
);
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export default ReviewNavbar;
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import GradingNav from "./GradingNav";
|
|
3
|
+
|
|
4
|
+
import styles from "./style.module.scss";
|
|
5
|
+
|
|
6
|
+
const ReviewNavbar: FC = () => {
|
|
7
|
+
return (
|
|
8
|
+
<div className={styles.reviewNavbar}>
|
|
9
|
+
<div aria-label="Indicateur de mode correction">Mode correction</div>
|
|
10
|
+
<div>
|
|
11
|
+
<GradingNav />
|
|
12
|
+
</div>
|
|
13
|
+
<div></div>
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default ReviewNavbar;
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
.reviewNavbar {
|
|
2
|
-
color-scheme: dark;
|
|
3
|
-
background-color: var(--surface-500);
|
|
4
|
-
--review-navbar-text-color: rgba(255, 255, 255, 0.95);
|
|
5
|
-
color: var(--review-navbar-text-color);
|
|
6
|
-
padding: 4px 16px;
|
|
7
|
-
display: flex;
|
|
8
|
-
align-items: center;
|
|
9
|
-
justify-content: space-between;
|
|
10
|
-
& :global(.p-button-secondary) {
|
|
11
|
-
border-color: var(--review-navbar-text-color);
|
|
12
|
-
color: var(--review-navbar-text-color);
|
|
13
|
-
}
|
|
14
|
-
& :global(.p-dropdown) {
|
|
15
|
-
border-color: var(--review-navbar-text-color);
|
|
16
|
-
border-left-width: 0;
|
|
17
|
-
border-right-width: 0;
|
|
18
|
-
}
|
|
19
|
-
:global(.dark-theme) & {
|
|
20
|
-
background-color: var(--surface-100);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
1
|
+
.reviewNavbar {
|
|
2
|
+
color-scheme: dark;
|
|
3
|
+
background-color: var(--surface-500);
|
|
4
|
+
--review-navbar-text-color: rgba(255, 255, 255, 0.95);
|
|
5
|
+
color: var(--review-navbar-text-color);
|
|
6
|
+
padding: 4px 16px;
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: space-between;
|
|
10
|
+
& :global(.p-button-secondary) {
|
|
11
|
+
border-color: var(--review-navbar-text-color);
|
|
12
|
+
color: var(--review-navbar-text-color);
|
|
13
|
+
}
|
|
14
|
+
& :global(.p-dropdown) {
|
|
15
|
+
border-color: var(--review-navbar-text-color);
|
|
16
|
+
border-left-width: 0;
|
|
17
|
+
border-right-width: 0;
|
|
18
|
+
}
|
|
19
|
+
:global(.dark-theme) & {
|
|
20
|
+
background-color: var(--surface-100);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import { FC, useEffect } from "react";
|
|
2
|
-
import { useAppDispatch, useAppSelector } from "../../../app/hooks";
|
|
3
|
-
import {
|
|
4
|
-
QuickAction,
|
|
5
|
-
selectSidebarActions,
|
|
6
|
-
setSidebarActions,
|
|
7
|
-
usePerformQuickAction,
|
|
8
|
-
} from "../navbarSlice";
|
|
9
|
-
import { Button } from "primereact/button";
|
|
10
|
-
import settings from "../../../settings";
|
|
11
|
-
|
|
12
|
-
const ActivitySidebarActions: FC<{}> = () => {
|
|
13
|
-
const sidebarActions = useAppSelector(selectSidebarActions);
|
|
14
|
-
const performQuickAction = usePerformQuickAction();
|
|
15
|
-
return (
|
|
16
|
-
<>
|
|
17
|
-
{sidebarActions.map((action) => (
|
|
18
|
-
<Button
|
|
19
|
-
aria-label={action.title}
|
|
20
|
-
key={action.title}
|
|
21
|
-
severity="secondary"
|
|
22
|
-
size="small"
|
|
23
|
-
icon={action.icon}
|
|
24
|
-
onClick={() => {
|
|
25
|
-
performQuickAction(action);
|
|
26
|
-
}}
|
|
27
|
-
outlined
|
|
28
|
-
label={action.title}
|
|
29
|
-
tooltipOptions={{
|
|
30
|
-
position: "left",
|
|
31
|
-
showDelay: settings.TOOLTIP_SHOW_DELAY,
|
|
32
|
-
}}
|
|
33
|
-
/>
|
|
34
|
-
))}
|
|
35
|
-
</>
|
|
36
|
-
);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
type ActivitySidebarActionsSetterProps = {
|
|
40
|
-
actions: QuickAction[];
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const ActivitySidebarActionsSetter: FC<
|
|
44
|
-
ActivitySidebarActionsSetterProps
|
|
45
|
-
> = (props) => {
|
|
46
|
-
const dispatch = useAppDispatch();
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
dispatch(setSidebarActions(props.actions));
|
|
49
|
-
return () => {
|
|
50
|
-
dispatch(setSidebarActions([]));
|
|
51
|
-
};
|
|
52
|
-
}, [props.actions]);
|
|
53
|
-
|
|
54
|
-
return <></>;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export default ActivitySidebarActions;
|
|
1
|
+
import { FC, useEffect } from "react";
|
|
2
|
+
import { useAppDispatch, useAppSelector } from "../../../app/hooks";
|
|
3
|
+
import {
|
|
4
|
+
QuickAction,
|
|
5
|
+
selectSidebarActions,
|
|
6
|
+
setSidebarActions,
|
|
7
|
+
usePerformQuickAction,
|
|
8
|
+
} from "../navbarSlice";
|
|
9
|
+
import { Button } from "primereact/button";
|
|
10
|
+
import settings from "../../../settings";
|
|
11
|
+
|
|
12
|
+
const ActivitySidebarActions: FC<{}> = () => {
|
|
13
|
+
const sidebarActions = useAppSelector(selectSidebarActions);
|
|
14
|
+
const performQuickAction = usePerformQuickAction();
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
{sidebarActions.map((action) => (
|
|
18
|
+
<Button
|
|
19
|
+
aria-label={action.title}
|
|
20
|
+
key={action.title}
|
|
21
|
+
severity="secondary"
|
|
22
|
+
size="small"
|
|
23
|
+
icon={action.icon}
|
|
24
|
+
onClick={() => {
|
|
25
|
+
performQuickAction(action);
|
|
26
|
+
}}
|
|
27
|
+
outlined
|
|
28
|
+
label={action.title}
|
|
29
|
+
tooltipOptions={{
|
|
30
|
+
position: "left",
|
|
31
|
+
showDelay: settings.TOOLTIP_SHOW_DELAY,
|
|
32
|
+
}}
|
|
33
|
+
/>
|
|
34
|
+
))}
|
|
35
|
+
</>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
type ActivitySidebarActionsSetterProps = {
|
|
40
|
+
actions: QuickAction[];
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const ActivitySidebarActionsSetter: FC<
|
|
44
|
+
ActivitySidebarActionsSetterProps
|
|
45
|
+
> = (props) => {
|
|
46
|
+
const dispatch = useAppDispatch();
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
dispatch(setSidebarActions(props.actions));
|
|
49
|
+
return () => {
|
|
50
|
+
dispatch(setSidebarActions([]));
|
|
51
|
+
};
|
|
52
|
+
}, [props.actions]);
|
|
53
|
+
|
|
54
|
+
return <></>;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default ActivitySidebarActions;
|