@learnpack/learnpack 5.0.240 → 5.0.246
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/publish.d.ts +1 -1
- package/lib/commands/publish.js +19 -14
- package/lib/commands/serve.js +87 -100
- package/lib/creatorDist/assets/{index-DJn8b8wj.js → index-CZYzWk3G.js} +3044 -3045
- package/lib/creatorDist/index.html +1 -1
- package/lib/models/creator.d.ts +1 -0
- package/lib/utils/api.d.ts +1 -0
- package/lib/utils/api.js +1 -1
- package/lib/utils/creatorSocket.d.ts +1 -1
- package/lib/utils/creatorSocket.js +10 -3
- package/lib/utils/rigoActions.d.ts +5 -0
- package/lib/utils/rigoActions.js +11 -1
- package/package.json +1 -1
- package/src/commands/publish.ts +26 -24
- package/src/commands/serve.ts +160 -140
- package/src/creator/src/App.tsx +3 -1
- package/src/creator/src/components/NotificationListener.tsx +1 -1
- package/src/creator/src/components/syllabus/SyllabusEditor.tsx +12 -16
- package/src/creator/src/utils/rigo.ts +3 -2
- package/src/creator/src/utils/store.ts +4 -1
- package/src/creatorDist/assets/{index-DJn8b8wj.js → index-CZYzWk3G.js} +3044 -3045
- package/src/creatorDist/index.html +1 -1
- package/src/models/creator.ts +1 -0
- package/src/ui/_app/app.css +1 -1
- package/src/ui/_app/app.js +367 -367
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/api.ts +2 -1
- package/src/utils/creatorSocket.ts +22 -16
- package/src/utils/rigoActions.ts +22 -0
package/src/commands/serve.ts
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
import { flags } from "@oclif/command"
|
2
2
|
|
3
|
-
// import { readDocument } from "../utils/readDocuments"
|
4
3
|
import { YoutubeTranscript } from "youtube-transcript"
|
5
4
|
import * as express from "express"
|
6
5
|
import * as cors from "cors"
|
@@ -31,6 +30,7 @@ import {
|
|
31
30
|
generateImage,
|
32
31
|
isPackageAuthor,
|
33
32
|
createStructuredPreviewReadme,
|
33
|
+
translateCourseMetadata,
|
34
34
|
} from "../utils/rigoActions"
|
35
35
|
import * as dotenv from "dotenv"
|
36
36
|
import {
|
@@ -65,15 +65,13 @@ function findLast<T>(
|
|
65
65
|
export const createLearnJson = (courseInfo: FormState) => {
|
66
66
|
// console.log("courseInfo to create learn json", courseInfo)
|
67
67
|
|
68
|
-
const expectedPreviewUrl = `https://${
|
69
|
-
courseInfo.title as string
|
70
|
-
)}.learn-pack.com/preview.png`
|
68
|
+
const expectedPreviewUrl = `https://${courseInfo.slug}.learn-pack.com/preview.png`
|
71
69
|
console.log("Preview url in generated learn.json", expectedPreviewUrl)
|
72
70
|
|
73
71
|
const language = courseInfo.language || "en"
|
74
72
|
|
75
73
|
const learnJson = {
|
76
|
-
slug:
|
74
|
+
slug: courseInfo.slug,
|
77
75
|
title:
|
78
76
|
language === "en" || language === "us" ?
|
79
77
|
{
|
@@ -106,27 +104,6 @@ const uploadFileToBucket = async (
|
|
106
104
|
await fileRef.save(Buffer.from(file, "utf8"))
|
107
105
|
}
|
108
106
|
|
109
|
-
const uploadImageToBucket = async (
|
110
|
-
bucket: Bucket,
|
111
|
-
url: string,
|
112
|
-
path: string
|
113
|
-
) => {
|
114
|
-
const response = await fetch(url)
|
115
|
-
if (!response.ok) {
|
116
|
-
throw new Error(`Failed to download image: ${response.statusText}`)
|
117
|
-
}
|
118
|
-
|
119
|
-
const contentType =
|
120
|
-
response.headers.get("content-type") || "application/octet-stream"
|
121
|
-
const buffer = await response.arrayBuffer()
|
122
|
-
|
123
|
-
const fileRef = bucket.file(path)
|
124
|
-
await fileRef.save(Buffer.from(buffer), {
|
125
|
-
resumable: false,
|
126
|
-
contentType,
|
127
|
-
})
|
128
|
-
}
|
129
|
-
|
130
107
|
const PARAMS = {
|
131
108
|
expected_grade_level: "8",
|
132
109
|
max_fkgl: 10,
|
@@ -135,41 +112,6 @@ const PARAMS = {
|
|
135
112
|
max_title_length: 50,
|
136
113
|
}
|
137
114
|
|
138
|
-
// app.post("/webhooks/:courseSlug/images/:imageId", async (req, res) => {
|
139
|
-
// const { courseSlug, imageId } = req.params
|
140
|
-
// const body = req.body
|
141
|
-
// console.log("RECEIVING IMAGE WEBHOOK", body)
|
142
|
-
|
143
|
-
// const imageUrl = body.image_url
|
144
|
-
// const imagePath = `courses/${courseSlug}/.learn/assets/${imageId}`
|
145
|
-
|
146
|
-
// const imageFile = bucket.file(imagePath)
|
147
|
-
// const [exists] = await imageFile.exists()
|
148
|
-
// if (!exists) {
|
149
|
-
// // Descargar la imagen
|
150
|
-
// const response = await fetch(imageUrl)
|
151
|
-
// if (!response.ok) {
|
152
|
-
// return res.status(400).json({
|
153
|
-
// status: "ERROR",
|
154
|
-
// message: "No se pudo descargar la imagen",
|
155
|
-
// })
|
156
|
-
// }
|
157
|
-
|
158
|
-
// const buffer = await response.arrayBuffer()
|
159
|
-
|
160
|
-
// // Guardar la imagen en el bucket
|
161
|
-
// await imageFile.save(new Uint8Array(buffer), {
|
162
|
-
// contentType: "image/png",
|
163
|
-
// })
|
164
|
-
// }
|
165
|
-
|
166
|
-
// emitToNotification(imageId, {
|
167
|
-
// status: "SUCCESS",
|
168
|
-
// message: "Image generated successfully",
|
169
|
-
// })
|
170
|
-
// res.json({ status: "SUCCESS" })
|
171
|
-
// })
|
172
|
-
|
173
115
|
export const processImage = async (
|
174
116
|
url: string,
|
175
117
|
description: string,
|
@@ -186,7 +128,6 @@ export const processImage = async (
|
|
186
128
|
prompt: description,
|
187
129
|
callbackUrl: webhookUrl,
|
188
130
|
})
|
189
|
-
// await uploadImageToBucket(bucket, res.image_url, imagePath)
|
190
131
|
|
191
132
|
// console.log("✅ Image", imagePath, "generated successfully!")
|
192
133
|
return true
|
@@ -236,7 +177,6 @@ const uploadInitialReadme = async (
|
|
236
177
|
}
|
237
178
|
|
238
179
|
const cleanFormState = (formState: FormState) => {
|
239
|
-
// keysToDelete: description, technologies, purpose
|
240
180
|
const {
|
241
181
|
description,
|
242
182
|
technologies,
|
@@ -252,6 +192,45 @@ const cleanFormState = (formState: FormState) => {
|
|
252
192
|
return rest
|
253
193
|
}
|
254
194
|
|
195
|
+
const createMultiLangAsset = async (
|
196
|
+
bucket: Bucket,
|
197
|
+
rigoToken: string,
|
198
|
+
bcToken: string,
|
199
|
+
courseSlug: string,
|
200
|
+
courseJson: any,
|
201
|
+
deployUrl: string
|
202
|
+
) => {
|
203
|
+
const availableLangs = Object.keys(courseJson.title)
|
204
|
+
console.log("AVAILABLE LANGUAGES to upload asset", availableLangs)
|
205
|
+
|
206
|
+
const all_translations: string[] = []
|
207
|
+
|
208
|
+
for (const lang of availableLangs) {
|
209
|
+
// eslint-disable-next-line no-await-in-loop
|
210
|
+
const indexReadme = await bucket.file(
|
211
|
+
`courses/${courseSlug}/README.${
|
212
|
+
lang === "us" || lang === "en" ? "md" : `${lang}.md`
|
213
|
+
}`
|
214
|
+
)
|
215
|
+
// eslint-disable-next-line no-await-in-loop
|
216
|
+
const [indexReadmeContent] = await indexReadme.download()
|
217
|
+
const indexReadmeString = indexReadmeContent.toString()
|
218
|
+
const b64IndexReadme = Buffer.from(indexReadmeString).toString("base64")
|
219
|
+
|
220
|
+
// eslint-disable-next-line no-await-in-loop
|
221
|
+
const asset = await handleAssetCreation(
|
222
|
+
{ token: bcToken, rigobotToken: rigoToken.trim() },
|
223
|
+
courseJson,
|
224
|
+
lang,
|
225
|
+
deployUrl,
|
226
|
+
b64IndexReadme,
|
227
|
+
all_translations
|
228
|
+
)
|
229
|
+
|
230
|
+
all_translations.push(asset.slug)
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
255
234
|
async function startExerciseGeneration(
|
256
235
|
bucket: Bucket,
|
257
236
|
rigoToken: string,
|
@@ -544,7 +523,6 @@ export default class ServeCommand extends SessionCommand {
|
|
544
523
|
const { courseSlug } = req.params
|
545
524
|
const body = req.body
|
546
525
|
|
547
|
-
console.log("RECEIVING INITIAL README WEBHOOK", body)
|
548
526
|
// Save the file as courses/courseSlug/README.md
|
549
527
|
const filePath = `courses/${courseSlug}/README.${
|
550
528
|
body.parsed.language_code === "us" ||
|
@@ -935,25 +913,34 @@ export default class ServeCommand extends SessionCommand {
|
|
935
913
|
|
936
914
|
app.post("/actions/translate", express.json(), async (req, res) => {
|
937
915
|
console.log("POST /actions/translate")
|
938
|
-
const { exerciseSlugs, languages, rigoToken } = req.body
|
916
|
+
const { exerciseSlugs, languages, rigoToken, currentLanguage } = req.body
|
939
917
|
const query = req.query
|
940
918
|
const courseSlug = query.slug
|
941
919
|
|
942
|
-
console.log("EXERCISE SLUGS", exerciseSlugs)
|
943
|
-
console.log("LANGUAGES", languages)
|
944
|
-
console.log("RIGO TOKEN", rigoToken)
|
945
|
-
|
946
920
|
if (!rigoToken) {
|
947
921
|
return res.status(400).json({ error: "RigoToken not found" })
|
948
922
|
}
|
949
923
|
|
950
924
|
const languagesToTranslate: string[] = languages.split(",")
|
951
925
|
|
926
|
+
const course = await bucket
|
927
|
+
.file(`courses/${courseSlug}/learn.json`)
|
928
|
+
.download()
|
929
|
+
|
930
|
+
const courseJson = JSON.parse(course.toString())
|
931
|
+
const languageCodes = new Set()
|
932
|
+
|
952
933
|
try {
|
953
934
|
await Promise.all(
|
954
935
|
exerciseSlugs.map(async (slug: string) => {
|
955
|
-
const readmePath = `courses/${courseSlug}/exercises/${slug}/README
|
936
|
+
const readmePath = `courses/${courseSlug}/exercises/${slug}/README${
|
937
|
+
currentLanguage === "us" || currentLanguage === "en" ?
|
938
|
+
"" :
|
939
|
+
`.${currentLanguage}`
|
940
|
+
}.md`
|
941
|
+
|
956
942
|
const readme = await bucket.file(readmePath).download()
|
943
|
+
|
957
944
|
await Promise.all(
|
958
945
|
languagesToTranslate.map(async (language: string) => {
|
959
946
|
const response = await translateExercise(rigoToken, {
|
@@ -963,14 +950,98 @@ export default class ServeCommand extends SessionCommand {
|
|
963
950
|
})
|
964
951
|
|
965
952
|
const translatedReadme = await bucket.file(
|
966
|
-
`courses/${courseSlug}/exercises/${slug}/README
|
953
|
+
`courses/${courseSlug}/exercises/${slug}/README${
|
954
|
+
response.parsed.output_language_code === "us" ||
|
955
|
+
response.parsed.output_language_code === "en" ?
|
956
|
+
"" :
|
957
|
+
`.${response.parsed.output_language_code}`
|
958
|
+
}.md`
|
967
959
|
)
|
968
960
|
await translatedReadme.save(response.parsed.translation)
|
961
|
+
|
962
|
+
languageCodes.add(response.parsed.output_language_code)
|
969
963
|
})
|
970
964
|
)
|
971
965
|
})
|
972
966
|
)
|
973
967
|
|
968
|
+
if (languageCodes.has("en")) {
|
969
|
+
languageCodes.delete("en")
|
970
|
+
languageCodes.add("us")
|
971
|
+
}
|
972
|
+
|
973
|
+
const currentLanguages = Object.keys(courseJson.title)
|
974
|
+
for (const languageCode of currentLanguages) {
|
975
|
+
if (languageCodes.has(languageCode)) {
|
976
|
+
languageCodes.delete(languageCode)
|
977
|
+
}
|
978
|
+
}
|
979
|
+
|
980
|
+
if ([...languageCodes].length > 0) {
|
981
|
+
console.log("TRANSLATING COURSE METADATA", languageCodes)
|
982
|
+
|
983
|
+
const translatedCourseMetadata = await Promise.all(
|
984
|
+
[...languageCodes].map(async languageCode => {
|
985
|
+
const result = await translateCourseMetadata(rigoToken, {
|
986
|
+
title: courseJson.title[currentLanguage],
|
987
|
+
description: courseJson.description[currentLanguage],
|
988
|
+
destination_lang_code: languageCode as string,
|
989
|
+
})
|
990
|
+
|
991
|
+
return {
|
992
|
+
languageCode,
|
993
|
+
title: result.parsed.title,
|
994
|
+
description: result.parsed.description,
|
995
|
+
}
|
996
|
+
})
|
997
|
+
)
|
998
|
+
|
999
|
+
for (const metadata of translatedCourseMetadata) {
|
1000
|
+
courseJson.title[metadata.languageCode as string] = metadata.title
|
1001
|
+
courseJson.description[metadata.languageCode as string] =
|
1002
|
+
metadata.description
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
await uploadFileToBucket(
|
1006
|
+
bucket,
|
1007
|
+
JSON.stringify(courseJson),
|
1008
|
+
`courses/${courseSlug}/learn.json`
|
1009
|
+
)
|
1010
|
+
|
1011
|
+
const previewReadme = await bucket.file(
|
1012
|
+
`courses/${courseSlug}/README${
|
1013
|
+
currentLanguage === "us" || currentLanguage === "en" ?
|
1014
|
+
"" :
|
1015
|
+
`.${currentLanguage}`
|
1016
|
+
}.md`
|
1017
|
+
)
|
1018
|
+
const [previewReadmeContent] = await previewReadme.download()
|
1019
|
+
const previewReadmeContentString = previewReadmeContent.toString()
|
1020
|
+
|
1021
|
+
await Promise.all(
|
1022
|
+
[...languageCodes].map(async languageCode => {
|
1023
|
+
const translatedPreviewReadme = await translateExercise(
|
1024
|
+
rigoToken,
|
1025
|
+
{
|
1026
|
+
text_to_translate: previewReadmeContentString,
|
1027
|
+
output_language: languageCode as string,
|
1028
|
+
exercise_slug: "preview-readme",
|
1029
|
+
}
|
1030
|
+
)
|
1031
|
+
|
1032
|
+
await bucket
|
1033
|
+
.file(
|
1034
|
+
`courses/${courseSlug}/README${
|
1035
|
+
languageCode === "us" || languageCode === "en" ?
|
1036
|
+
"" :
|
1037
|
+
`.${languageCode}`
|
1038
|
+
}.md`
|
1039
|
+
)
|
1040
|
+
.save(translatedPreviewReadme.parsed.translation)
|
1041
|
+
})
|
1042
|
+
)
|
1043
|
+
}
|
1044
|
+
|
974
1045
|
return res.status(200).json({ message: "Translated exercises" })
|
975
1046
|
} catch (error) {
|
976
1047
|
console.log(error, "ERROR")
|
@@ -979,6 +1050,8 @@ export default class ServeCommand extends SessionCommand {
|
|
979
1050
|
})
|
980
1051
|
|
981
1052
|
app.delete("/exercise/:slug/delete", async (req, res) => {
|
1053
|
+
console.log("DELETE /exercise/:slug/delete")
|
1054
|
+
|
982
1055
|
const { slug } = req.params
|
983
1056
|
const query = req.query
|
984
1057
|
const courseSlug = query.slug
|
@@ -1032,13 +1105,17 @@ export default class ServeCommand extends SessionCommand {
|
|
1032
1105
|
res.json(sidebar)
|
1033
1106
|
} catch (error: any) {
|
1034
1107
|
if (error.code === 404) {
|
1035
|
-
console.log("SIDEBAR FILE NOT FOUND", courseSlug)
|
1036
|
-
|
1037
1108
|
const { exercises } = await buildConfig(bucket, courseSlug)
|
1038
1109
|
|
1039
1110
|
const exerciseSlugsArray = exercises.map(exercise => exercise.slug)
|
1040
1111
|
const sidebar = await createInitialSidebar(exerciseSlugsArray)
|
1041
1112
|
|
1113
|
+
await uploadFileToBucket(
|
1114
|
+
bucket,
|
1115
|
+
JSON.stringify(sidebar),
|
1116
|
+
`courses/${courseSlug}/.learn/sidebar.json`
|
1117
|
+
)
|
1118
|
+
|
1042
1119
|
if (rigoToken) {
|
1043
1120
|
const { fixedSidebar } = await checkAndFixSidebarPure(
|
1044
1121
|
sidebar,
|
@@ -1053,20 +1130,9 @@ export default class ServeCommand extends SessionCommand {
|
|
1053
1130
|
)
|
1054
1131
|
}
|
1055
1132
|
|
1056
|
-
await uploadFileToBucket(
|
1057
|
-
bucket,
|
1058
|
-
JSON.stringify(sidebar),
|
1059
|
-
`courses/${courseSlug}/.learn/sidebar.json`
|
1060
|
-
)
|
1061
1133
|
return res.status(200).json(fixedSidebar)
|
1062
1134
|
}
|
1063
1135
|
|
1064
|
-
await uploadFileToBucket(
|
1065
|
-
bucket,
|
1066
|
-
JSON.stringify(sidebar),
|
1067
|
-
`courses/${courseSlug}/.learn/sidebar.json`
|
1068
|
-
)
|
1069
|
-
|
1070
1136
|
return res.status(200).json(sidebar)
|
1071
1137
|
}
|
1072
1138
|
|
@@ -1075,35 +1141,6 @@ export default class ServeCommand extends SessionCommand {
|
|
1075
1141
|
}
|
1076
1142
|
})
|
1077
1143
|
|
1078
|
-
// app.get("/test/:slug", (req, res) => {
|
1079
|
-
// emitToCourse(req.params.slug, "course-creation", {
|
1080
|
-
// lesson: "000-welcome-to-bird-domestication",
|
1081
|
-
// status: "generating",
|
1082
|
-
// log: "Hello",
|
1083
|
-
// })
|
1084
|
-
// emitToCourse(req.params.slug, "course-creation", {
|
1085
|
-
// lesson: "000-welcome-to-bird-domestication",
|
1086
|
-
// status: "generating",
|
1087
|
-
// log: "Hello",
|
1088
|
-
// })
|
1089
|
-
// emitToCourse(req.params.slug, "course-creation", {
|
1090
|
-
// lesson: "000-welcome-to-bird-domestication",
|
1091
|
-
// status: "generating",
|
1092
|
-
// log: "Hello broder",
|
1093
|
-
// })
|
1094
|
-
// emitToCourse(req.params.slug, "course-creation", {
|
1095
|
-
// lesson: "000-welcome-to-bird-domestication",
|
1096
|
-
// status: "done",
|
1097
|
-
// log: "Hello broder",
|
1098
|
-
// })
|
1099
|
-
// emitToCourse(req.params.slug, "course-creation", {
|
1100
|
-
// lesson: "other",
|
1101
|
-
// status: "generating",
|
1102
|
-
// log: "Hello",
|
1103
|
-
// })
|
1104
|
-
// res.send({ message: "Course creation started" })
|
1105
|
-
// })
|
1106
|
-
|
1107
1144
|
app.get("/technologies", async (req, res) => {
|
1108
1145
|
console.log("GET /technologies")
|
1109
1146
|
|
@@ -1143,7 +1180,7 @@ export default class ServeCommand extends SessionCommand {
|
|
1143
1180
|
return res.status(400).json({ error: "Missing tokens" })
|
1144
1181
|
}
|
1145
1182
|
|
1146
|
-
const courseSlug =
|
1183
|
+
const courseSlug = syllabus.courseInfo.slug
|
1147
1184
|
|
1148
1185
|
const tutorialDir = `courses/${courseSlug}`
|
1149
1186
|
const learnJson = createLearnJson(syllabus.courseInfo)
|
@@ -1241,7 +1278,7 @@ export default class ServeCommand extends SessionCommand {
|
|
1241
1278
|
|
1242
1279
|
return res.json({
|
1243
1280
|
message: "Course created",
|
1244
|
-
slug:
|
1281
|
+
slug: syllabus.courseInfo.slug,
|
1245
1282
|
})
|
1246
1283
|
})
|
1247
1284
|
|
@@ -1356,6 +1393,7 @@ export default class ServeCommand extends SessionCommand {
|
|
1356
1393
|
app.post("/actions/publish/:slug", async (req, res) => {
|
1357
1394
|
try {
|
1358
1395
|
const { slug } = req.params
|
1396
|
+
const { currentLanguage } = req.body
|
1359
1397
|
const rigoToken = req.header("x-rigo-token")
|
1360
1398
|
const bcToken = req.header("x-breathecode-token")
|
1361
1399
|
// const { academyId, categoryId } = req.body
|
@@ -1371,8 +1409,6 @@ export default class ServeCommand extends SessionCommand {
|
|
1371
1409
|
slug
|
1372
1410
|
)
|
1373
1411
|
|
1374
|
-
// const fixedSlug = fixSlugLength(slug)
|
1375
|
-
|
1376
1412
|
const prefix = `courses/${slug}/`
|
1377
1413
|
const tmpRoot = path.join(os.tmpdir(), `learnpack-${slug}`)
|
1378
1414
|
const buildRoot = path.join(tmpRoot, "build")
|
@@ -1409,11 +1445,6 @@ export default class ServeCommand extends SessionCommand {
|
|
1409
1445
|
selectedLang = availableLangs[0]
|
1410
1446
|
}
|
1411
1447
|
|
1412
|
-
// console.log(availableLangs, "AVAILABLE LANGs")
|
1413
|
-
// console.log(selectedLang, "SELECTED LANG")
|
1414
|
-
// console.log(title, "TITLE")
|
1415
|
-
|
1416
|
-
// 5) Inyectar placeholders en index.html
|
1417
1448
|
const idxTpl = fs.readFileSync(path.join(uiSrc, "index.html"), "utf-8")
|
1418
1449
|
const idxHtml = idxTpl
|
1419
1450
|
.replace(/{{title}}/g, title)
|
@@ -1480,29 +1511,18 @@ export default class ServeCommand extends SessionCommand {
|
|
1480
1511
|
{
|
1481
1512
|
headers: {
|
1482
1513
|
...form.getHeaders(),
|
1483
|
-
Authorization:
|
1514
|
+
Authorization: "Token " + rigoToken.trim(),
|
1484
1515
|
},
|
1485
1516
|
}
|
1486
1517
|
)
|
1487
1518
|
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
}`
|
1494
|
-
)
|
1495
|
-
const [indexReadmeContent] = await indexReadme.download()
|
1496
|
-
const indexReadmeString = indexReadmeContent.toString()
|
1497
|
-
const b64IndexReadme =
|
1498
|
-
Buffer.from(indexReadmeString).toString("base64")
|
1499
|
-
|
1500
|
-
await handleAssetCreation(
|
1501
|
-
{ token: bcToken, rigobotToken: rigoToken },
|
1519
|
+
await createMultiLangAsset(
|
1520
|
+
bucket,
|
1521
|
+
rigoToken,
|
1522
|
+
bcToken,
|
1523
|
+
slug,
|
1502
1524
|
fullConfig.config,
|
1503
|
-
|
1504
|
-
rigoRes.data.url,
|
1505
|
-
b64IndexReadme
|
1525
|
+
rigoRes.data.url
|
1506
1526
|
)
|
1507
1527
|
|
1508
1528
|
rimraf.sync(tmpRoot)
|
package/src/creator/src/App.tsx
CHANGED
@@ -26,6 +26,7 @@ import ResumeCourseModal from "./components/ResumeCourseModal"
|
|
26
26
|
import { possiblePurposes, PurposeSelector } from "./components/PurposeSelector"
|
27
27
|
import { useTranslation } from "react-i18next"
|
28
28
|
import NotificationListener from "./components/NotificationListener"
|
29
|
+
import { slugify } from "./utils/creatorUtils"
|
29
30
|
|
30
31
|
function App() {
|
31
32
|
const navigate = useNavigate()
|
@@ -410,7 +411,8 @@ function App() {
|
|
410
411
|
lessons,
|
411
412
|
courseInfo: {
|
412
413
|
...formState,
|
413
|
-
title:
|
414
|
+
title: res.parsed.title,
|
415
|
+
slug: slugify(fixTitleLength(res.parsed.title)),
|
414
416
|
description: res.parsed.description,
|
415
417
|
language:
|
416
418
|
res.parsed.languageCode || formState.language || "en",
|
@@ -13,7 +13,6 @@ import {
|
|
13
13
|
// reWriteTitle,
|
14
14
|
useConsumableCall,
|
15
15
|
isValidRigoToken,
|
16
|
-
fixTitleLength,
|
17
16
|
} from "../../utils/lib"
|
18
17
|
|
19
18
|
import Loader from "../Loader"
|
@@ -96,25 +95,23 @@ const SyllabusEditor: React.FC = () => {
|
|
96
95
|
return
|
97
96
|
}
|
98
97
|
|
99
|
-
let
|
100
|
-
let
|
101
|
-
let isAvailable = await isSlugAvailable(slug)
|
98
|
+
let newSlug = syllabus.courseInfo.slug
|
99
|
+
let isAvailable = await isSlugAvailable(syllabus.courseInfo.slug)
|
102
100
|
|
103
101
|
while (!isAvailable) {
|
104
|
-
if (
|
105
|
-
|
102
|
+
if (newSlug.length > 50) {
|
103
|
+
newSlug = newSlug.slice(0, 44)
|
106
104
|
}
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
isAvailable = await isSlugAvailable(slug)
|
105
|
+
newSlug = newSlug + "-" + randomUUID()
|
106
|
+
newSlug = newSlug.slice(0, 50)
|
107
|
+
isAvailable = await isSlugAvailable(newSlug)
|
111
108
|
}
|
112
109
|
|
113
110
|
push({
|
114
111
|
...syllabus,
|
115
112
|
courseInfo: {
|
116
113
|
...syllabus.courseInfo,
|
117
|
-
|
114
|
+
slug: newSlug,
|
118
115
|
},
|
119
116
|
})
|
120
117
|
}
|
@@ -215,9 +212,7 @@ const SyllabusEditor: React.FC = () => {
|
|
215
212
|
|
216
213
|
const timeout = setTimeout(() => {
|
217
214
|
cleanAll()
|
218
|
-
window.location.href = `/preview/${
|
219
|
-
syllabus.courseInfo.title || ""
|
220
|
-
)}?token=${auth.bcToken}&language=${syllabus.courseInfo.language}`
|
215
|
+
window.location.href = `/preview/${syllabus.courseInfo.slug}?token=${auth.bcToken}&language=${syllabus.courseInfo.language}`
|
221
216
|
}, 8000)
|
222
217
|
try {
|
223
218
|
await createCourse(syllabus, tokenToUse, auth.bcToken)
|
@@ -230,6 +225,8 @@ const SyllabusEditor: React.FC = () => {
|
|
230
225
|
|
231
226
|
if (!syllabus) return null
|
232
227
|
|
228
|
+
console.log(syllabus.courseInfo)
|
229
|
+
|
233
230
|
return isGenerating ? (
|
234
231
|
<>
|
235
232
|
<Loader
|
@@ -253,8 +250,7 @@ It may take a moment..."
|
|
253
250
|
lessons: lessons,
|
254
251
|
courseInfo: {
|
255
252
|
...syllabus.courseInfo,
|
256
|
-
title:
|
257
|
-
fixTitleLength(res.parsed.title) || syllabus.courseInfo.title,
|
253
|
+
title: res.parsed.title || syllabus.courseInfo.title,
|
258
254
|
description:
|
259
255
|
res.parsed.description || syllabus.courseInfo.description,
|
260
256
|
language:
|
@@ -19,8 +19,9 @@ export const publicInteractiveCreation = async (
|
|
19
19
|
const webhookUrl = `${
|
20
20
|
DEV_MODE
|
21
21
|
? "https://9cw5zmww-3000.use2.devtunnels.ms"
|
22
|
-
:
|
23
|
-
|
22
|
+
: // TODO: remove this
|
23
|
+
// : window.location.origin
|
24
|
+
"https://9cw5zmww-3000.use2.devtunnels.ms"
|
24
25
|
}/notifications/${randomUID}`
|
25
26
|
|
26
27
|
const response = await axios.post(
|
@@ -11,6 +11,7 @@ export type FormState = {
|
|
11
11
|
hasContentIndex: boolean
|
12
12
|
contentIndex: string
|
13
13
|
purpose: string
|
14
|
+
slug: string
|
14
15
|
language?: string
|
15
16
|
isCompleted: boolean
|
16
17
|
variables: string[]
|
@@ -85,6 +86,7 @@ const useStore = create<Store>()(
|
|
85
86
|
formState: {
|
86
87
|
description: "",
|
87
88
|
duration: 0,
|
89
|
+
slug: "",
|
88
90
|
hasContentIndex: false,
|
89
91
|
contentIndex: "",
|
90
92
|
purpose: "",
|
@@ -119,6 +121,7 @@ const useStore = create<Store>()(
|
|
119
121
|
resetFormState: () =>
|
120
122
|
set({
|
121
123
|
formState: {
|
124
|
+
slug: "",
|
122
125
|
currentStep: "description",
|
123
126
|
description: "",
|
124
127
|
duration: 0,
|
@@ -169,7 +172,7 @@ const useStore = create<Store>()(
|
|
169
172
|
formState: {
|
170
173
|
description: "",
|
171
174
|
duration: 0,
|
172
|
-
|
175
|
+
slug: "",
|
173
176
|
language: "en",
|
174
177
|
technologies: [],
|
175
178
|
hasContentIndex: false,
|