@learnpack/learnpack 5.0.290 → 5.0.292
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/lib/commands/init.js +42 -42
- package/lib/commands/serve.js +505 -36
- package/lib/creatorDist/assets/{index-C39zeF3W.css → index-CacFtcN8.css} +31 -0
- package/lib/creatorDist/assets/{index-7zTdUX04.js → index-DOEfLGDQ.js} +1426 -1374
- package/lib/creatorDist/index.html +2 -2
- package/lib/models/creator.d.ts +4 -0
- package/lib/utils/api.d.ts +1 -1
- package/lib/utils/api.js +2 -1
- package/lib/utils/configBuilder.js +20 -1
- package/lib/utils/rigoActions.d.ts +14 -0
- package/lib/utils/rigoActions.js +43 -1
- package/package.json +1 -1
- package/src/commands/init.ts +655 -650
- package/src/commands/serve.ts +865 -106
- package/src/creator/src/App.tsx +13 -14
- package/src/creator/src/components/FileUploader.tsx +2 -68
- package/src/creator/src/components/LessonItem.tsx +47 -8
- package/src/creator/src/components/Login.tsx +0 -6
- package/src/creator/src/components/syllabus/ContentIndex.tsx +11 -0
- package/src/creator/src/components/syllabus/SyllabusEditor.tsx +6 -1
- package/src/creator/src/index.css +227 -217
- package/src/creator/src/locales/en.json +2 -2
- package/src/creator/src/locales/es.json +2 -2
- package/src/creator/src/utils/lib.ts +470 -468
- package/src/creator/src/utils/rigo.ts +85 -85
- package/src/creatorDist/assets/{index-C39zeF3W.css → index-CacFtcN8.css} +31 -0
- package/src/creatorDist/assets/{index-7zTdUX04.js → index-DOEfLGDQ.js} +1426 -1374
- package/src/creatorDist/index.html +2 -2
- package/src/models/creator.ts +2 -0
- package/src/ui/_app/app.css +1 -1
- package/src/ui/_app/app.js +420 -418
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/api.ts +2 -1
- package/src/utils/configBuilder.ts +100 -82
- package/src/utils/rigoActions.ts +73 -0
package/src/creator/src/App.tsx
CHANGED
@@ -123,13 +123,12 @@ function App() {
|
|
123
123
|
}
|
124
124
|
|
125
125
|
if (description) {
|
126
|
-
console.log("description", description)
|
127
126
|
setFormState({
|
128
127
|
description: description,
|
129
128
|
})
|
130
129
|
}
|
131
130
|
if (duration && !isNaN(parseInt(duration))) {
|
132
|
-
if (["
|
131
|
+
if (["15", "30", "60"].includes(duration)) {
|
133
132
|
const durationInt = parseInt(duration)
|
134
133
|
console.log("duration", durationInt)
|
135
134
|
setFormState({
|
@@ -295,7 +294,7 @@ function App() {
|
|
295
294
|
onFinish={(purpose) => {
|
296
295
|
setFormState({
|
297
296
|
purpose: purpose,
|
298
|
-
currentStep: "
|
297
|
+
currentStep: "duration",
|
299
298
|
})
|
300
299
|
}}
|
301
300
|
/>
|
@@ -308,6 +307,17 @@ function App() {
|
|
308
307
|
required: true,
|
309
308
|
content: (
|
310
309
|
<div className="flex flex-col md:flex-row gap-2">
|
310
|
+
<SelectableCard
|
311
|
+
title={t("stepWizard.durationCard.15")}
|
312
|
+
// subtitle="This is a tutorial that will take 15 minutes to complete"
|
313
|
+
onClick={() => {
|
314
|
+
setFormState({
|
315
|
+
duration: 15,
|
316
|
+
currentStep: "verifyHuman",
|
317
|
+
})
|
318
|
+
}}
|
319
|
+
selected={formState.duration === 15}
|
320
|
+
/>
|
311
321
|
<SelectableCard
|
312
322
|
title={t("stepWizard.durationCard.30")}
|
313
323
|
// subtitle="This is a tutorial that will take 30 minutes to complete"
|
@@ -330,17 +340,6 @@ function App() {
|
|
330
340
|
}}
|
331
341
|
selected={formState.duration === 60}
|
332
342
|
/>
|
333
|
-
<SelectableCard
|
334
|
-
title={t("stepWizard.durationCard.120")}
|
335
|
-
// subtitle="This is a tutorial that will take 2 hours to complete"
|
336
|
-
onClick={() => {
|
337
|
-
setFormState({
|
338
|
-
duration: 120,
|
339
|
-
currentStep: "verifyHuman",
|
340
|
-
})
|
341
|
-
}}
|
342
|
-
selected={formState.duration === 120}
|
343
|
-
/>
|
344
343
|
</div>
|
345
344
|
),
|
346
345
|
},
|
@@ -8,67 +8,6 @@ import { DEV_MODE, RIGOBOT_HOST } from "../utils/constants"
|
|
8
8
|
import axios from "axios"
|
9
9
|
import { useTranslation } from "react-i18next"
|
10
10
|
|
11
|
-
// `
|
12
|
-
// app.post("/read-document", upload.single("file"), async (req, res) => {
|
13
|
-
// console.log("READING A DOCUMENT")
|
14
|
-
// const publicToken = req.header("x-public-token")
|
15
|
-
// if (!publicToken) {
|
16
|
-
// return res.status(400).json({ error: "Public token is required" })
|
17
|
-
// }
|
18
|
-
|
19
|
-
// try {
|
20
|
-
// // eslint-disable-next-line
|
21
|
-
// // @ts-ignore
|
22
|
-
// if (!req.file) {
|
23
|
-
// return res.status(400).json({ error: "Missing file" })
|
24
|
-
// }
|
25
|
-
|
26
|
-
// console.log("PUBLIC TOKEN", publicToken)
|
27
|
-
|
28
|
-
// const resultId = `document-read-${Date.now()}-${Math.floor(
|
29
|
-
// Math.random() * 1e6
|
30
|
-
// )}`
|
31
|
-
|
32
|
-
// const webhookUrl = `${deploymentURL}/notifications/${resultId}`
|
33
|
-
// console.log("WEBHOOK URL", webhookUrl)
|
34
|
-
// // Construir form-data para enviar al servidor proxy
|
35
|
-
// const formData = new FormData()
|
36
|
-
// // eslint-disable-next-line
|
37
|
-
// // @ts-ignore
|
38
|
-
// formData.append("file", req.file.buffer, {
|
39
|
-
// // eslint-disable-next-line
|
40
|
-
// // @ts-ignore
|
41
|
-
// filename: req.file.originalname,
|
42
|
-
// // eslint-disable-next-line
|
43
|
-
// // @ts-ignore
|
44
|
-
// contentType: req.file.mimetype,
|
45
|
-
// })
|
46
|
-
// formData.append("webhook_callback_url", webhookUrl)
|
47
|
-
|
48
|
-
// try {
|
49
|
-
// const response = await axios.post(
|
50
|
-
// `${RIGOBOT_HOST}/v1/learnpack/public/tools/read-document`,
|
51
|
-
// formData,
|
52
|
-
// {
|
53
|
-
// headers: {
|
54
|
-
// ...formData.getHeaders(),
|
55
|
-
// Authorization: `Token ${publicToken.trim()}`,
|
56
|
-
// },
|
57
|
-
// }
|
58
|
-
// )
|
59
|
-
// } catch (error) {
|
60
|
-
// console.error("❌ Error in /read-document:", error)
|
61
|
-
// return res.status(500).json({ error: (error as Error).message })
|
62
|
-
// }
|
63
|
-
|
64
|
-
// return res.json({ notificationId: resultId, status: "PROCESSING" })
|
65
|
-
// } catch (error) {
|
66
|
-
// console.error("❌ Error in /read-document:", error)
|
67
|
-
// return res.status(500).json({ error: (error as Error).message })
|
68
|
-
// }
|
69
|
-
// })
|
70
|
-
// `
|
71
|
-
|
72
11
|
const socketClient = new CreatorSocket("")
|
73
12
|
|
74
13
|
const allowedTypes = [
|
@@ -155,12 +94,6 @@ const UploadedFileCard = ({ idx, file }: { idx: number; file: ParsedFile }) => {
|
|
155
94
|
}
|
156
95
|
onClick={
|
157
96
|
() => setUploadedFiles(uploadedFiles.filter((_, i) => i !== idx))
|
158
|
-
// Set the file as error
|
159
|
-
// setUploadedFiles(
|
160
|
-
// uploadedFiles.map((f, i) =>
|
161
|
-
// i === idx ? { ...f, status: "ERROR" } : f
|
162
|
-
// )
|
163
|
-
// )
|
164
97
|
}
|
165
98
|
>
|
166
99
|
{SVGS.trash}
|
@@ -202,7 +135,8 @@ const FileUploader: React.FC<FileUploaderProps> = ({
|
|
202
135
|
|
203
136
|
const webhookUrl = `${
|
204
137
|
DEV_MODE
|
205
|
-
? "https://
|
138
|
+
? "https://1gm40gnb-3000.use2.devtunnels.ms"
|
139
|
+
// : "https://1gm40gnb-3000.use2.devtunnels.ms"
|
206
140
|
: window.location.origin
|
207
141
|
}/notifications/${resultId}`
|
208
142
|
formData.append("webhook_callback_url", webhookUrl)
|
@@ -13,6 +13,7 @@ export interface Lesson {
|
|
13
13
|
type: "READ" | "CODE" | "QUIZ"
|
14
14
|
description: string
|
15
15
|
duration?: number
|
16
|
+
locked?: boolean
|
16
17
|
}
|
17
18
|
|
18
19
|
const typeToEmoji: Record<string, string> = {
|
@@ -26,6 +27,7 @@ interface LessonItemProps {
|
|
26
27
|
isNew: boolean
|
27
28
|
onChange: (uid: string, newTitle: string) => void
|
28
29
|
onRemove: () => void
|
30
|
+
onToggleLock?: (uid: string) => void
|
29
31
|
}
|
30
32
|
|
31
33
|
function cleanFloatString(input: string): string {
|
@@ -47,6 +49,7 @@ export const LessonItem: React.FC<LessonItemProps> = ({
|
|
47
49
|
lesson,
|
48
50
|
onChange,
|
49
51
|
onRemove,
|
52
|
+
onToggleLock,
|
50
53
|
isNew,
|
51
54
|
}) => {
|
52
55
|
const mode = useStore((state) => state.mode)
|
@@ -57,13 +60,20 @@ export const LessonItem: React.FC<LessonItemProps> = ({
|
|
57
60
|
<div
|
58
61
|
className={`flex items-center space-x-2 relative rounded-md p-3 ${
|
59
62
|
isNew ? "border border-learnpack-blue appear" : "border border-gray-200"
|
60
|
-
} ${hasDecimalPart(lesson.id.toString() || "0") ? "ml-6" : ""}
|
63
|
+
} ${hasDecimalPart(lesson.id.toString() || "0") ? "ml-6" : ""} ${
|
64
|
+
lesson.locked ? "bg-yellow-50 border-yellow-300" : ""
|
65
|
+
}`}
|
61
66
|
>
|
62
|
-
{isNew && <span className="
|
67
|
+
{isNew && <span className="yellow-ball"></span>}
|
63
68
|
|
64
69
|
{mode === "teacher" && (
|
65
70
|
<>
|
66
71
|
<span className="index-circle">{cleanFloatString(lesson.id)}</span>
|
72
|
+
{lesson.locked && (
|
73
|
+
<span className="text-yellow-600 text-sm" title="Lesson is locked">
|
74
|
+
🔒
|
75
|
+
</span>
|
76
|
+
)}
|
67
77
|
</>
|
68
78
|
)}
|
69
79
|
|
@@ -92,20 +102,49 @@ export const LessonItem: React.FC<LessonItemProps> = ({
|
|
92
102
|
|
93
103
|
{mode === "teacher" && (
|
94
104
|
<>
|
105
|
+
<button
|
106
|
+
onClick={() => onToggleLock?.(lesson.uid)}
|
107
|
+
className={`cursor-pointer ${
|
108
|
+
lesson.locked
|
109
|
+
? "text-yellow-600 hover:text-yellow-700"
|
110
|
+
: "text-gray-400 hover:text-yellow-600"
|
111
|
+
}`}
|
112
|
+
title={lesson.locked ? "Unlock lesson" : "Lock lesson"}
|
113
|
+
>
|
114
|
+
🔒
|
115
|
+
</button>
|
95
116
|
<button
|
96
117
|
onClick={() => {
|
97
|
-
|
98
|
-
|
99
|
-
|
118
|
+
if (!lesson.locked) {
|
119
|
+
setIsEditing(!isEditing)
|
120
|
+
if (inputRef.current) {
|
121
|
+
onChange(lesson.uid, inputRef.current.value)
|
122
|
+
}
|
100
123
|
}
|
101
124
|
}}
|
102
|
-
className=
|
125
|
+
className={`${
|
126
|
+
lesson.locked
|
127
|
+
? "text-gray-300 cursor-not-allowed"
|
128
|
+
: "text-gray-500 hover:text-blue-500 cursor-pointer"
|
129
|
+
}`}
|
130
|
+
disabled={lesson.locked}
|
131
|
+
title={lesson.locked ? "Cannot edit locked lesson" : "Edit lesson"}
|
103
132
|
>
|
104
133
|
{SVGS.pen}
|
105
134
|
</button>
|
106
135
|
<button
|
107
|
-
onClick={() =>
|
108
|
-
|
136
|
+
onClick={() => {
|
137
|
+
if (!lesson.locked) {
|
138
|
+
onRemove()
|
139
|
+
}
|
140
|
+
}}
|
141
|
+
className={`${
|
142
|
+
lesson.locked
|
143
|
+
? "text-gray-300 cursor-not-allowed"
|
144
|
+
: "text-red-500 hover:text-red-700 cursor-pointer"
|
145
|
+
}`}
|
146
|
+
disabled={lesson.locked}
|
147
|
+
title={lesson.locked ? "Cannot delete locked lesson" : "Delete lesson"}
|
109
148
|
>
|
110
149
|
{SVGS.trash}
|
111
150
|
</button>
|
@@ -241,12 +241,6 @@ export default function Login({ onFinish }: { onFinish: () => void }) {
|
|
241
241
|
<p className="text-gray-700 m-0">
|
242
242
|
{t("login.youDontHaveAnAccount")}
|
243
243
|
</p>
|
244
|
-
{/* <button
|
245
|
-
className="text-blue-600 font-medium cursor-pointer"
|
246
|
-
onClick={() => setShowSignup(true)}
|
247
|
-
>
|
248
|
-
Register here.
|
249
|
-
</button> */}
|
250
244
|
<a
|
251
245
|
href={`https://www.learnpack.co/register?callback=${encodeURIComponent(window.location.href)}`}
|
252
246
|
target="_blank"
|
@@ -184,6 +184,15 @@ export const ContentIndex = ({
|
|
184
184
|
})
|
185
185
|
}
|
186
186
|
|
187
|
+
const handleToggleLock = (uid: string) => {
|
188
|
+
push({
|
189
|
+
...syllabus,
|
190
|
+
lessons: syllabus.lessons.map((lesson) =>
|
191
|
+
lesson.uid === uid ? { ...lesson, locked: !lesson.locked } : lesson
|
192
|
+
),
|
193
|
+
})
|
194
|
+
}
|
195
|
+
|
187
196
|
const addLessonAfter = (index: number, id: string) => {
|
188
197
|
const newLesson: Lesson = {
|
189
198
|
id: (parseFloat(id) + 0.1).toFixed(1),
|
@@ -192,6 +201,7 @@ export const ContentIndex = ({
|
|
192
201
|
type: "READ",
|
193
202
|
duration: 2,
|
194
203
|
description: "Hello World",
|
204
|
+
locked: false,
|
195
205
|
}
|
196
206
|
const updated = [...syllabus.lessons]
|
197
207
|
updated.splice(index + 1, 0, newLesson)
|
@@ -258,6 +268,7 @@ export const ContentIndex = ({
|
|
258
268
|
lesson={lesson}
|
259
269
|
onChange={handleChange}
|
260
270
|
onRemove={() => handleRemove(lesson)}
|
271
|
+
onToggleLock={handleToggleLock}
|
261
272
|
isNew={Boolean(
|
262
273
|
previousSyllabus &&
|
263
274
|
previousSyllabus &&
|
@@ -163,6 +163,8 @@ const SyllabusEditor: React.FC = () => {
|
|
163
163
|
{ type: "assistant", content: "" },
|
164
164
|
])
|
165
165
|
|
166
|
+
const lessonsText = JSON.stringify(syllabus.lessons)
|
167
|
+
|
166
168
|
const res = await publicInteractiveCreation(
|
167
169
|
{
|
168
170
|
courseInfo:
|
@@ -170,7 +172,10 @@ const SyllabusEditor: React.FC = () => {
|
|
170
172
|
`\nThe following technologies are available, choose up to 3 from the following list: <techs>${technologies
|
171
173
|
.filter((t) => t.lang === syllabus.courseInfo.language)
|
172
174
|
.map((t) => t.slug)
|
173
|
-
.join(", ")}</techs
|
175
|
+
.join(", ")}</techs> \nThe following lessons are already in the syllabus: ${lessonsText}
|
176
|
+
|
177
|
+
You must NEVER delete lessons that are marked as locked.
|
178
|
+
`,
|
174
179
|
prevInteractions:
|
175
180
|
messages
|
176
181
|
.map((message) => `${message.type}: ${message.content}`)
|