Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
math_tutor_dev
public_math_tutor
Commits
9a38c477
Commit
9a38c477
authored
Mar 02, 2026
by
Kantz
Browse files
wechsel der Aufgabe nun auch innerhalb des Chats möglich
parent
4cb2901e
Changes
4
Hide whitespace changes
Inline
Side-by-side
math-tutor/frontend/src/components/Task/TaskPanel.tsx
View file @
9a38c477
...
...
@@ -17,6 +17,11 @@ type TaskPanelProps = {
tasksError
?:
string
|
null
;
onTaskFileChange
?:
(
fileId
:
string
)
=>
void
;
onTaskChange
?:
(
taskId
:
string
)
=>
void
;
onChangeTaskArea
?:
()
=>
void
;
onPreviousTask
?:
()
=>
void
;
isPreviousTaskDisabled
?:
boolean
;
onNextTask
?:
()
=>
void
;
isNextTaskDisabled
?:
boolean
;
};
export
default
function
TaskPanel
({
...
...
@@ -30,6 +35,11 @@ export default function TaskPanel({
tasksError
,
onTaskFileChange
,
onTaskChange
,
onChangeTaskArea
,
onPreviousTask
,
isPreviousTaskDisabled
=
false
,
onNextTask
,
isNextTaskDisabled
=
false
,
}:
TaskPanelProps
)
{
const
taskDisplayRef
=
useRef
<
HTMLDivElement
|
null
>
(
null
);
...
...
@@ -49,7 +59,13 @@ export default function TaskPanel({
<
div
className
=
"task-panel-header"
>
<
div
className
=
"task-panel-title"
>
{
t
(
"
task
"
)
}
</
div
>
{
readOnly
?
(
<
div
className
=
"task-panel-lock"
>
{
t
(
"
taskLocked
"
)
}
</
div
>
<
button
type
=
"button"
className
=
"btn task-panel-change-btn"
onClick
=
{
onChangeTaskArea
}
>
{
t
(
"
changeTaskArea
"
)
}
</
button
>
)
:
(
<
div
className
=
"task-panel-controls"
>
<
select
...
...
@@ -98,6 +114,27 @@ export default function TaskPanel({
<
div
className
=
"task-panel-content"
ref
=
{
taskDisplayRef
}
>
{
selectedTaskText
||
t
(
"
noTaskSelected
"
)
}
</
div
>
{
readOnly
?
(
<
div
className
=
"task-panel-nav"
>
<
button
type
=
"button"
className
=
"btn task-panel-nav-btn"
onClick
=
{
onPreviousTask
}
disabled
=
{
!
onPreviousTask
||
isPreviousTaskDisabled
}
>
{
t
(
"
previousTask
"
)
}
</
button
>
<
button
type
=
"button"
className
=
"btn task-panel-nav-btn"
onClick
=
{
onNextTask
}
disabled
=
{
!
onNextTask
||
isNextTaskDisabled
}
>
{
t
(
"
nextTask
"
)
}
</
button
>
</
div
>
)
:
null
}
{
tasksError
?
<
div
className
=
"task-panel-error"
>
{
tasksError
}
</
div
>
:
null
}
</
section
>
);
...
...
math-tutor/frontend/src/i18n.ts
View file @
9a38c477
...
...
@@ -50,7 +50,9 @@
taskFile
:
"
Task Set
"
,
taskId
:
"
Task ID
"
,
solveWithTutor
:
"
Solve with Tutor
"
,
taskLocked
:
"
Task locked
"
,
changeTaskArea
:
"
Change Task Area
"
,
previousTask
:
"
Previous Task
"
,
nextTask
:
"
Next Task
"
,
},
de
:
{
chats
:
"
Chats
"
,
...
...
@@ -107,7 +109,9 @@
taskFile
:
"
Aufgabenset
"
,
taskId
:
"
Aufgaben-ID
"
,
solveWithTutor
:
"
Mit Tutor lösen
"
,
taskLocked
:
"
Aufgabe fixiert
"
,
changeTaskArea
:
"
Aufgabengebiet ändern
"
,
previousTask
:
"
Vorherige Aufgabe
"
,
nextTask
:
"
Nächste Aufgabe
"
,
},
}
as
const
;
...
...
math-tutor/frontend/src/pages/ChatPage.tsx
View file @
9a38c477
...
...
@@ -9,7 +9,7 @@ import type { ChatMessage } from "../components/Chat/MessageList";
import
type
{
RetrievedDoc
}
from
"
../components/Retrieval/DocPanel
"
;
import
{
t
}
from
"
../i18n
"
;
import
{
selectTask
}
from
"
../api/taskApi
"
;
import
{
useTutorSession
}
from
"
../state/tutorSession
"
;
import
{
createSessionId
,
useTutorSession
}
from
"
../state/tutorSession
"
;
const
initialMessages
:
ChatMessage
[]
=
[];
...
...
@@ -99,6 +99,7 @@ export default function ChatPage() {
isTasksInitialized
,
selectedTaskRef
,
selectedTask
,
selectedTaskFile
,
taskLocked
,
lockTask
,
unlockTask
,
...
...
@@ -181,6 +182,40 @@ export default function ChatPage() {
return
{
bySourceKey
,
bySlug
};
},
[
directChildren
,
taskChildren
,
indirectChildren
,
subsections
,
sections
]);
const
nextTaskRef
=
useMemo
(()
=>
{
if
(
!
selectedTaskFile
||
!
selectedTaskRef
)
{
return
null
;
}
const
currentIndex
=
selectedTaskFile
.
tasks
.
findIndex
(
(
task
)
=>
task
.
task_id
===
selectedTaskRef
.
taskId
);
if
(
currentIndex
<
0
)
{
return
null
;
}
const
nextTask
=
selectedTaskFile
.
tasks
[
currentIndex
+
1
];
if
(
!
nextTask
)
{
return
null
;
}
return
{
fileId
:
selectedTaskFile
.
file_id
,
taskId
:
nextTask
.
task_id
};
},
[
selectedTaskFile
,
selectedTaskRef
]);
const
previousTaskRef
=
useMemo
(()
=>
{
if
(
!
selectedTaskFile
||
!
selectedTaskRef
)
{
return
null
;
}
const
currentIndex
=
selectedTaskFile
.
tasks
.
findIndex
(
(
task
)
=>
task
.
task_id
===
selectedTaskRef
.
taskId
);
if
(
currentIndex
<=
0
)
{
return
null
;
}
const
previousTask
=
selectedTaskFile
.
tasks
[
currentIndex
-
1
];
if
(
!
previousTask
)
{
return
null
;
}
return
{
fileId
:
selectedTaskFile
.
file_id
,
taskId
:
previousTask
.
task_id
};
},
[
selectedTaskFile
,
selectedTaskRef
]);
const
handleSend
=
async
()
=>
{
const
trimmed
=
draft
.
trim
();
if
(
!
trimmed
)
{
...
...
@@ -427,6 +462,67 @@ export default function ChatPage() {
navigate
(
isTaskModeEnabled
?
"
/select-task
"
:
"
/chat
"
);
};
const
handleSwitchTask
=
async
(
target
:
{
fileId
:
string
;
taskId
:
string
}
|
null
)
=>
{
if
(
!
target
)
{
return
;
}
if
(
messages
.
length
)
{
setIsArchiving
(
true
);
try
{
await
fetch
(
`/api/chat/archive`
,
{
method
:
"
POST
"
,
headers
:
{
"
Content-Type
"
:
"
application/json
"
},
body
:
JSON
.
stringify
({
messages
:
messages
.
map
((
message
)
=>
({
role
:
message
.
role
,
text
:
message
.
text
,
})),
draft
:
chatSessionId
,
}),
});
}
catch
(
error
)
{
void
error
;
}
finally
{
setIsArchiving
(
false
);
}
}
const
nextSessionId
=
createSessionId
();
resetChatState
();
setChatSessionId
(
nextSessionId
);
setTaskRef
(
target
);
lockTask
();
try
{
await
selectTask
({
draft
:
nextSessionId
,
fileId
:
target
.
fileId
,
taskId
:
target
.
taskId
,
});
}
catch
(
error
)
{
void
error
;
return
;
}
await
loadArchives
();
navigate
(
"
/chat
"
);
};
const
handleNextTask
=
async
()
=>
{
await
handleSwitchTask
(
nextTaskRef
);
};
const
handlePreviousTask
=
async
()
=>
{
await
handleSwitchTask
(
previousTaskRef
);
};
const
handleChangeTaskArea
=
()
=>
{
unlockTask
();
navigate
(
"
/select-task
"
);
};
const
handleOpenSidebar
=
()
=>
{
setIsSidebarOpen
(
true
);
void
loadArchives
();
...
...
@@ -605,6 +701,11 @@ export default function ChatPage() {
selectedTaskText
=
{
selectedTask
.
fullText
}
selectedFileLabel
=
{
selectedTask
.
title
||
selectedTask
.
fileId
}
selectedTaskId
=
{
selectedTask
.
taskId
}
onChangeTaskArea
=
{
handleChangeTaskArea
}
onPreviousTask
=
{
handlePreviousTask
}
isPreviousTaskDisabled
=
{
!
previousTaskRef
||
isArchiving
}
onNextTask
=
{
handleNextTask
}
isNextTaskDisabled
=
{
!
nextTaskRef
||
isArchiving
}
/>
)
:
null
}
...
...
math-tutor/frontend/src/styles/theme.css
View file @
9a38c477
...
...
@@ -618,16 +618,6 @@ body {
align-self
:
flex-end
;
}
.task-panel-lock
{
margin-left
:
auto
;
font-size
:
12px
;
color
:
#6f675d
;
border
:
1px
solid
#d8d1c4
;
border-radius
:
999px
;
padding
:
4px
8px
;
background
:
#fff
;
}
.task-panel-meta
{
display
:
flex
;
justify-content
:
space-between
;
...
...
@@ -636,6 +626,25 @@ body {
color
:
#6f675d
;
}
.task-panel-change-btn
{
margin-left
:
auto
;
padding
:
4px
10px
;
font-size
:
11px
;
}
.task-panel-nav-btn
{
padding
:
4px
10px
;
font-size
:
11px
;
}
.task-panel-nav
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
font-size
:
11px
;
gap
:
10px
;
}
@media
(
max-width
:
900px
)
{
.task-select-controls
{
grid-template-columns
:
1
fr
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment