@learnpack/learnpack 5.0.358 → 5.0.360
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 +0 -10
- package/lib/commands/publish.js +52 -168
- package/lib/commands/serve.js +52 -116
- package/lib/creatorDist/assets/{index-zrPponAn.css → index-B7s5Nmq8.css} +59 -0
- package/lib/creatorDist/assets/{index-D6pmbMe9.js → index-GYxGB_X0.js} +22609 -22363
- package/lib/creatorDist/index.html +2 -2
- package/lib/utils/api.d.ts +62 -15
- package/lib/utils/api.js +124 -45
- package/lib/utils/assetResolver.d.ts +116 -0
- package/lib/utils/assetResolver.js +268 -0
- package/lib/utils/assetSync.d.ts +48 -0
- package/lib/utils/assetSync.js +267 -0
- package/lib/utils/creatorUtilities.d.ts +1 -0
- package/lib/utils/creatorUtilities.js +17 -1
- package/package.json +1 -1
- package/src/commands/publish.ts +61 -255
- package/src/commands/serve.ts +65 -140
- package/src/creator/src/App.test.tsx +338 -0
- package/src/creator/src/App.tsx +152 -26
- package/src/creator/src/components/CourseLanguagePicker.tsx +51 -0
- package/src/creator/src/components/LanguageDetectionModal.tsx +29 -9
- package/src/creator/src/components/StepWizard.tsx +11 -3
- package/src/creator/src/components/Uploader.test.tsx +65 -0
- package/src/creator/src/components/Uploader.tsx +9 -3
- package/src/creator/src/locales/en.json +7 -0
- package/src/creator/src/locales/es.json +7 -0
- package/src/creator/src/utils/courseLanguage.test.ts +215 -0
- package/src/creator/src/utils/courseLanguage.ts +173 -0
- package/src/creator/src/utils/creationRequest.test.ts +104 -0
- package/src/creator/src/utils/creationRequest.ts +63 -0
- package/src/creator/src/utils/store.ts +7 -0
- package/src/creatorDist/assets/{index-zrPponAn.css → index-B7s5Nmq8.css} +59 -0
- package/src/creatorDist/assets/{index-D6pmbMe9.js → index-GYxGB_X0.js} +22609 -22363
- package/src/creatorDist/index.html +2 -2
- package/src/ui/_app/app.css +1 -1
- package/src/ui/_app/app.js +2105 -2105
- package/src/ui/_app/sw.js +13 -0
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/api.ts +157 -42
- package/src/utils/assetResolver.ts +368 -0
- package/src/utils/assetSync.ts +343 -0
- package/src/utils/awsCredentials.ts +57 -57
- package/src/utils/creatorUtilities.ts +16 -0
- package/src/utils/descriptions/publishStage.ts +394 -394
- package/src/utils/descriptions/resumePublication.ts +217 -217
- package/src/utils/descriptions/s3Storage.ts +214 -214
- package/src/utils/s3/packageManifestBackfill.ts +771 -771
|
@@ -1,14 +1,4 @@
|
|
|
1
1
|
import SessionCommand from "../utils/SessionCommand";
|
|
2
|
-
type ExistingAssetInfo = {
|
|
3
|
-
lang: string;
|
|
4
|
-
slug: string;
|
|
5
|
-
exists: boolean;
|
|
6
|
-
academyId?: number;
|
|
7
|
-
};
|
|
8
|
-
export declare const handleAssetCreation: (sessionPayload: {
|
|
9
|
-
token: string;
|
|
10
|
-
rigobotToken: string;
|
|
11
|
-
}, learnJson: any, selectedLang: string, learnpackDeployUrl: string, b64IndexReadme: string, academyId: number | undefined, learnpackId: number, preflightInfo?: ExistingAssetInfo, all_translations?: string[]) => Promise<any>;
|
|
12
2
|
declare class BuildCommand extends SessionCommand {
|
|
13
3
|
static description: string;
|
|
14
4
|
static flags: {
|
package/lib/commands/publish.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.handleAssetCreation = void 0;
|
|
4
3
|
/* eslint-disable arrow-parens */
|
|
5
4
|
/* eslint-disable unicorn/no-array-for-each */
|
|
6
5
|
const child_process_1 = require("child_process");
|
|
@@ -20,181 +19,55 @@ const rigoActions_1 = require("../utils/rigoActions");
|
|
|
20
19
|
const misc_1 = require("../utils/misc");
|
|
21
20
|
const creatorUtilities_1 = require("../utils/creatorUtilities");
|
|
22
21
|
const branding_1 = require("../utils/branding");
|
|
22
|
+
const assetResolver_1 = require("../utils/assetResolver");
|
|
23
|
+
const assetSync_1 = require("../utils/assetSync");
|
|
23
24
|
const uploadZipEndpont = api_1.RIGOBOT_HOST + "/v1/learnpack/upload";
|
|
24
|
-
const getAvailableLangs = (learnJson) => {
|
|
25
|
-
const langs = Object.keys((learnJson === null || learnJson === void 0 ? void 0 : learnJson.title) || {});
|
|
26
|
-
return langs.filter((l) => typeof l === "string" && l.length > 0);
|
|
27
|
-
};
|
|
28
25
|
const getDefaultLang = (learnJson) => {
|
|
29
|
-
const availableLangs = getAvailableLangs(learnJson);
|
|
26
|
+
const availableLangs = (0, assetResolver_1.getAvailableLangs)(learnJson);
|
|
30
27
|
if (availableLangs.length === 0)
|
|
31
28
|
return "en";
|
|
32
29
|
return availableLangs.includes("en") ? "en" : availableLangs[0];
|
|
33
30
|
};
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
return "";
|
|
37
|
-
const direct = translations[lang];
|
|
38
|
-
if (typeof direct === "string" && direct.trim().length > 0)
|
|
39
|
-
return direct;
|
|
40
|
-
for (const fb of fallbackLangs) {
|
|
41
|
-
const v = translations[fb];
|
|
42
|
-
if (typeof v === "string" && v.trim().length > 0)
|
|
43
|
-
return v;
|
|
44
|
-
}
|
|
45
|
-
const firstKey = Object.keys(translations)[0];
|
|
46
|
-
const first = firstKey ? translations[firstKey] : "";
|
|
47
|
-
return typeof first === "string" ? first : "";
|
|
48
|
-
};
|
|
49
|
-
const getExistingAssetsInfo = async (token, learnJson) => {
|
|
50
|
-
const availableLangs = getAvailableLangs(learnJson);
|
|
51
|
-
const results = [];
|
|
52
|
-
for (const lang of availableLangs) {
|
|
53
|
-
const assetTitle = getLocalizedValue(learnJson === null || learnJson === void 0 ? void 0 : learnJson.title, lang);
|
|
54
|
-
if (!assetTitle)
|
|
55
|
-
continue;
|
|
56
|
-
let slug = (0, creatorUtilities_1.slugify)(assetTitle).slice(0, 47);
|
|
57
|
-
slug = `${slug}-${lang}`;
|
|
58
|
-
// eslint-disable-next-line no-await-in-loop
|
|
59
|
-
const { exists, academyId } = await api_1.default.doesAssetExists(token, slug);
|
|
60
|
-
results.push({ lang, slug, exists, academyId });
|
|
61
|
-
}
|
|
62
|
-
return results;
|
|
63
|
-
};
|
|
64
|
-
const determinePublishAcademyMode = (existingAssets) => {
|
|
65
|
-
const academyIds = existingAssets
|
|
66
|
-
.filter((a) => a.exists && a.academyId !== undefined)
|
|
67
|
-
.map((a) => a.academyId);
|
|
68
|
-
const unique = [...new Set(academyIds)];
|
|
69
|
-
if (unique.length === 0)
|
|
70
|
-
return { type: "select" };
|
|
71
|
-
if (unique.length === 1)
|
|
72
|
-
return { type: "locked", academyId: unique[0] };
|
|
73
|
-
return { type: "conflict", academies: unique };
|
|
74
|
-
};
|
|
75
|
-
const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, learnpackDeployUrl, b64IndexReadme, academyId, learnpackId, preflightInfo, all_translations = []) => {
|
|
76
|
-
const category = "uncategorized";
|
|
31
|
+
const readReadmeFromDisk = async (lang) => {
|
|
32
|
+
const readmePath = path.join(process.cwd(), `README${(0, creatorUtilities_1.getReadmeExtension)(lang)}`);
|
|
77
33
|
try {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (!assetTitle) {
|
|
82
|
-
throw new Error(`Missing learn.json title for language "${selectedLang}"`);
|
|
83
|
-
}
|
|
84
|
-
let slug = (0, creatorUtilities_1.slugify)(assetTitle).slice(0, 47);
|
|
85
|
-
slug = `${slug}-${selectedLang}`;
|
|
86
|
-
// Use pre-flight info when available to avoid an extra GET request
|
|
87
|
-
const { exists, academyId: existingAcademyId } = preflightInfo !== null && preflightInfo !== void 0 ? preflightInfo : (await api_1.default.doesAssetExists(sessionPayload.token, slug));
|
|
88
|
-
// const technologies: unknown[] = Array.isArray(learnJson?.technologies) ?
|
|
89
|
-
// learnJson.technologies :
|
|
90
|
-
// []
|
|
91
|
-
if (!exists) {
|
|
92
|
-
console_1.default.info("Asset does not exist in this academy, creating it");
|
|
93
|
-
const assetPayload = {
|
|
94
|
-
slug: slug,
|
|
95
|
-
title: assetTitle,
|
|
96
|
-
lang: selectedLang,
|
|
97
|
-
graded: true,
|
|
98
|
-
description: assetDescription,
|
|
99
|
-
learnpack_deploy_url: learnpackDeployUrl,
|
|
100
|
-
// technologies: technologies.map((tech: unknown) =>
|
|
101
|
-
// String(tech).toLowerCase().replace(/\s+/g, "-")
|
|
102
|
-
// ),
|
|
103
|
-
technologies: [],
|
|
104
|
-
url: learnpackDeployUrl,
|
|
105
|
-
category: category,
|
|
106
|
-
owner: user.id,
|
|
107
|
-
author: user.id,
|
|
108
|
-
preview: learnJson.preview,
|
|
109
|
-
readme_raw: b64IndexReadme,
|
|
110
|
-
all_translations,
|
|
111
|
-
learnpack_id: learnpackId,
|
|
112
|
-
};
|
|
113
|
-
if (academyId !== undefined) {
|
|
114
|
-
assetPayload.academy_id = academyId;
|
|
115
|
-
}
|
|
116
|
-
const asset = await api_1.default.createAsset(sessionPayload.token, assetPayload);
|
|
117
|
-
try {
|
|
118
|
-
await api_1.default.updateRigoPackage(sessionPayload.rigobotToken.trim(), learnJson.slug, {
|
|
119
|
-
asset_id: asset.id,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
catch (error) {
|
|
123
|
-
console_1.default.error("Error updating Rigo package:", error);
|
|
124
|
-
}
|
|
125
|
-
console_1.default.info("Asset created with id", asset.id);
|
|
126
|
-
return asset;
|
|
127
|
-
}
|
|
128
|
-
console_1.default.info("Asset exists, updating it");
|
|
129
|
-
const updatePayload = {
|
|
130
|
-
graded: true,
|
|
131
|
-
learnpack_deploy_url: learnpackDeployUrl,
|
|
132
|
-
title: assetTitle,
|
|
133
|
-
category: category,
|
|
134
|
-
description: assetDescription,
|
|
135
|
-
all_translations,
|
|
136
|
-
learnpack_id: learnpackId,
|
|
137
|
-
};
|
|
138
|
-
// Only set academy when the asset has none yet and the user selected one
|
|
139
|
-
if (existingAcademyId === undefined && academyId !== undefined) {
|
|
140
|
-
updatePayload.academy_id = academyId;
|
|
141
|
-
}
|
|
142
|
-
const asset = await api_1.default.updateAsset(sessionPayload.token, slug, updatePayload);
|
|
143
|
-
try {
|
|
144
|
-
await api_1.default.updateRigoPackage(sessionPayload.rigobotToken.trim(), learnJson.slug, {
|
|
145
|
-
asset_id: asset.id,
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
console_1.default.error("Error updating Rigo package:", error);
|
|
150
|
-
}
|
|
151
|
-
console_1.default.info("Asset updated with id", asset.id);
|
|
152
|
-
return asset;
|
|
34
|
+
return fs.existsSync(readmePath) ?
|
|
35
|
+
fs.readFileSync(readmePath, "utf-8") :
|
|
36
|
+
"";
|
|
153
37
|
}
|
|
154
38
|
catch (error) {
|
|
155
|
-
console_1.default.error("Error
|
|
156
|
-
|
|
39
|
+
console_1.default.error("Error reading index readme:", error);
|
|
40
|
+
return "";
|
|
157
41
|
}
|
|
158
42
|
};
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const availableLangs = getAvailableLangs(learnJson);
|
|
162
|
-
if (availableLangs.length === 0) {
|
|
43
|
+
const syncAssetsFromDisk = async (sessionPayload, learnJson, deployUrl, selectedAcademyId, resolution) => {
|
|
44
|
+
if ((0, assetResolver_1.getAvailableLangs)(learnJson).length === 0) {
|
|
163
45
|
console_1.default.error("No languages found in learn.json.title. Add at least one language (e.g. title.en).");
|
|
164
46
|
return;
|
|
165
47
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
48
|
+
// The pre-upload resolution is reused unless the package did not exist in
|
|
49
|
+
// Rigobot yet (first publish): the upload has just created it.
|
|
50
|
+
const result = await (0, assetSync_1.syncPackageAssets)({
|
|
51
|
+
bcToken: sessionPayload.token,
|
|
52
|
+
rigoToken: sessionPayload.rigobotToken,
|
|
53
|
+
packageSlug: learnJson.slug,
|
|
54
|
+
learnJson,
|
|
55
|
+
deployUrl,
|
|
56
|
+
academyId: selectedAcademyId,
|
|
57
|
+
readReadme: readReadmeFromDisk,
|
|
58
|
+
resolution: resolution.learnpackId === null ? undefined : resolution,
|
|
59
|
+
});
|
|
60
|
+
for (const warning of result.warnings)
|
|
61
|
+
console_1.default.warning(warning);
|
|
62
|
+
for (const synced of result.synced) {
|
|
63
|
+
console_1.default.info(`Asset ${synced.action} for "${synced.lang}": #${synced.asset.id} ${synced.asset.slug}`);
|
|
170
64
|
}
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
let indexReadmeString = "";
|
|
175
|
-
try {
|
|
176
|
-
if (fs.existsSync(readmePath)) {
|
|
177
|
-
indexReadmeString = fs.readFileSync(readmePath, "utf-8");
|
|
178
|
-
}
|
|
65
|
+
for (const error of result.errors) {
|
|
66
|
+
if (error.kind === "lang_error") {
|
|
67
|
+
console_1.default.error(`Asset for "${error.lang}": ${error.error.detail}`);
|
|
179
68
|
}
|
|
180
|
-
|
|
181
|
-
console_1.default.error(
|
|
182
|
-
indexReadmeString = "";
|
|
183
|
-
}
|
|
184
|
-
const b64IndexReadme = Buffer.from(indexReadmeString).toString("base64");
|
|
185
|
-
const preflightInfo = existingAssetsInfo.find((a) => a.lang === lang);
|
|
186
|
-
try {
|
|
187
|
-
// eslint-disable-next-line no-await-in-loop
|
|
188
|
-
const asset = await (0, exports.handleAssetCreation)(sessionPayload, learnJson, lang, deployUrl, b64IndexReadme, selectedAcademyId, learnpackId, preflightInfo, all_translations);
|
|
189
|
-
if (!asset) {
|
|
190
|
-
console_1.default.debug("Could not create/update asset for lang", lang);
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
all_translations.push(asset.slug);
|
|
194
|
-
}
|
|
195
|
-
catch (error) {
|
|
196
|
-
console_1.default.error("Error creating asset for language", lang, error);
|
|
197
|
-
// Continue with other languages
|
|
69
|
+
else {
|
|
70
|
+
console_1.default.error(error.error.detail);
|
|
198
71
|
}
|
|
199
72
|
}
|
|
200
73
|
};
|
|
@@ -313,8 +186,19 @@ class BuildCommand extends SessionCommand_1.default {
|
|
|
313
186
|
process.exit(1);
|
|
314
187
|
}
|
|
315
188
|
console_1.default.info("Checking existing assets...");
|
|
316
|
-
const
|
|
317
|
-
|
|
189
|
+
const resolution = await (0, assetResolver_1.resolvePackageAssets)({
|
|
190
|
+
bcToken: sessionPayload.token,
|
|
191
|
+
rigoToken: rigoToken,
|
|
192
|
+
packageSlug: learnJson.slug,
|
|
193
|
+
learnJson,
|
|
194
|
+
});
|
|
195
|
+
for (const warning of resolution.warnings)
|
|
196
|
+
console_1.default.warning(warning);
|
|
197
|
+
if (resolution.packageState === "unknown") {
|
|
198
|
+
console_1.default.error(`${resolution.packageError}. Existing assets cannot be checked, so publishing now could create duplicates. Try again later.`);
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
const academyMode = (0, assetResolver_1.determineAcademyMode)(resolution);
|
|
318
202
|
let selectedAcademyId;
|
|
319
203
|
if (academyMode.type === "conflict") {
|
|
320
204
|
console_1.default.warning(`Some of your assets are associated with different academies ` +
|
|
@@ -380,9 +264,9 @@ class BuildCommand extends SessionCommand_1.default {
|
|
|
380
264
|
if (fs.existsSync(indexHtmlPath)) {
|
|
381
265
|
let indexHtmlContent = fs.readFileSync(indexHtmlPath, "utf-8");
|
|
382
266
|
const selectedLang = getDefaultLang(learnJson);
|
|
383
|
-
const description = getLocalizedValue(learnJson === null || learnJson === void 0 ? void 0 : learnJson.description, selectedLang) ||
|
|
267
|
+
const description = (0, assetSync_1.getLocalizedValue)(learnJson === null || learnJson === void 0 ? void 0 : learnJson.description, selectedLang) ||
|
|
384
268
|
"LearnPack is awesome!";
|
|
385
|
-
const title = getLocalizedValue(learnJson === null || learnJson === void 0 ? void 0 : learnJson.title, selectedLang) ||
|
|
269
|
+
const title = (0, assetSync_1.getLocalizedValue)(learnJson === null || learnJson === void 0 ? void 0 : learnJson.title, selectedLang) ||
|
|
386
270
|
"LearnPack: Interactive Learning as a Service";
|
|
387
271
|
const previewUrl = learnJson.preview || (0, branding_1.getFallbackPreviewUrl)();
|
|
388
272
|
// Replace placeholders and the <title>Old title </title> tag for a new tag with the title
|
|
@@ -402,9 +286,9 @@ class BuildCommand extends SessionCommand_1.default {
|
|
|
402
286
|
if (fs.existsSync(manifestPWA)) {
|
|
403
287
|
let manifestPWAContent = fs.readFileSync(manifestPWA, "utf-8");
|
|
404
288
|
const selectedLang = getDefaultLang(learnJson);
|
|
405
|
-
const courseTitle = getLocalizedValue(learnJson === null || learnJson === void 0 ? void 0 : learnJson.title, selectedLang) ||
|
|
406
|
-
getLocalizedValue(learnJson === null || learnJson === void 0 ? void 0 : learnJson.title, "us") ||
|
|
407
|
-
getLocalizedValue(learnJson === null || learnJson === void 0 ? void 0 : learnJson.title, "en") ||
|
|
289
|
+
const courseTitle = (0, assetSync_1.getLocalizedValue)(learnJson === null || learnJson === void 0 ? void 0 : learnJson.title, selectedLang) ||
|
|
290
|
+
(0, assetSync_1.getLocalizedValue)(learnJson === null || learnJson === void 0 ? void 0 : learnJson.title, "us") ||
|
|
291
|
+
(0, assetSync_1.getLocalizedValue)(learnJson === null || learnJson === void 0 ? void 0 : learnJson.title, "en") ||
|
|
408
292
|
"LearnPack";
|
|
409
293
|
manifestPWAContent = manifestPWAContent.replace("{{course_title}}", courseTitle);
|
|
410
294
|
const courseShortName = { answer: "testing-tutorial" };
|
|
@@ -461,7 +345,7 @@ class BuildCommand extends SessionCommand_1.default {
|
|
|
461
345
|
console.log(res.data);
|
|
462
346
|
fs.unlinkSync(zipFilePath);
|
|
463
347
|
this.removeDirectory(buildDir);
|
|
464
|
-
await
|
|
348
|
+
await syncAssetsFromDisk({ token: sessionPayload.token, rigobotToken: rigoToken }, learnJson, res.data.url, selectedAcademyId, resolution);
|
|
465
349
|
}
|
|
466
350
|
catch (error) {
|
|
467
351
|
if (axios_1.default.isAxiosError(error)) {
|
package/lib/commands/serve.js
CHANGED
|
@@ -31,7 +31,8 @@ const misc_1 = require("../utils/misc");
|
|
|
31
31
|
const configBuilder_1 = require("../utils/configBuilder");
|
|
32
32
|
const creatorUtilities_2 = require("../utils/creatorUtilities");
|
|
33
33
|
const sidebarGenerator_1 = require("../utils/sidebarGenerator");
|
|
34
|
-
const
|
|
34
|
+
const assetResolver_1 = require("../utils/assetResolver");
|
|
35
|
+
const assetSync_1 = require("../utils/assetSync");
|
|
35
36
|
const export_1 = require("../utils/export");
|
|
36
37
|
const router_1 = require("../services/ingest/http/router");
|
|
37
38
|
const bucketIo_1 = require("../utils/coursePackage/bucketIo");
|
|
@@ -319,94 +320,34 @@ const cleanFormState = (formState) => {
|
|
|
319
320
|
const cleanFormStateForSyllabus = (formState) => {
|
|
320
321
|
return Object.assign(Object.assign({}, formState), { description: formState.description, technologies: formState.technologies, contentIndex: formState.contentIndex, purposse: undefined, duration: undefined, hasContentIndex: undefined, variables: undefined, currentStep: undefined, language: undefined, isCompleted: undefined });
|
|
321
322
|
};
|
|
322
|
-
const getLocalizedValue = (translations, lang, fallbackLangs = ["en", "us"]) => {
|
|
323
|
-
if (!translations || typeof translations !== "object")
|
|
324
|
-
return "";
|
|
325
|
-
const direct = translations[lang];
|
|
326
|
-
if (typeof direct === "string" && direct.trim().length > 0)
|
|
327
|
-
return direct;
|
|
328
|
-
for (const fb of fallbackLangs) {
|
|
329
|
-
const v = translations[fb];
|
|
330
|
-
if (typeof v === "string" && v.trim().length > 0)
|
|
331
|
-
return v;
|
|
332
|
-
}
|
|
333
|
-
const firstKey = Object.keys(translations)[0];
|
|
334
|
-
const first = firstKey ? translations[firstKey] : "";
|
|
335
|
-
return typeof first === "string" ? first : "";
|
|
336
|
-
};
|
|
337
|
-
function assetSyncErrorDetail(err) {
|
|
338
|
-
if (typeof (err === null || err === void 0 ? void 0 : err.detail) === "string")
|
|
339
|
-
return err.detail;
|
|
340
|
-
if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string")
|
|
341
|
-
return err.message;
|
|
342
|
-
try {
|
|
343
|
-
return JSON.stringify(err);
|
|
344
|
-
}
|
|
345
|
-
catch (_a) {
|
|
346
|
-
return String(err);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
323
|
const createMultiLangAsset = async (bucket, rigoToken, bcToken, courseSlug, courseJson, deployUrl, academyId) => {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
if (learnpackId === null) {
|
|
353
|
-
return {
|
|
354
|
-
errors: [
|
|
355
|
-
{
|
|
356
|
-
kind: "package_error",
|
|
357
|
-
error: {
|
|
358
|
-
detail: "Could not resolve Learnpack package id; assets not synced to Breathecode.",
|
|
359
|
-
},
|
|
360
|
-
},
|
|
361
|
-
],
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
const availableLangs = Object.keys(courseJson.title);
|
|
365
|
-
console.log("AVAILABLE LANGUAGES to upload asset", availableLangs);
|
|
366
|
-
const all_translations = [];
|
|
367
|
-
const errors = [];
|
|
368
|
-
for (const lang of availableLangs) {
|
|
369
|
-
// eslint-disable-next-line no-await-in-loop
|
|
370
|
-
const indexReadme = await bucket.file(`courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(lang)}`);
|
|
371
|
-
let indexReadmeString = "";
|
|
324
|
+
const readReadme = async (lang) => {
|
|
325
|
+
const indexReadme = bucket.file(`courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(lang)}`);
|
|
372
326
|
try {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
indexReadmeString = indexReadmeContent.toString();
|
|
327
|
+
const [content] = await indexReadme.download();
|
|
328
|
+
return content.toString();
|
|
376
329
|
}
|
|
377
330
|
catch (error) {
|
|
378
331
|
console.error("Error downloading index readme", error);
|
|
379
332
|
// TODO: Trigger generation of the index readme
|
|
380
|
-
|
|
381
|
-
}
|
|
382
|
-
const b64IndexReadme = buffer_1.Buffer.from(indexReadmeString).toString("base64");
|
|
383
|
-
try {
|
|
384
|
-
// eslint-disable-next-line no-await-in-loop
|
|
385
|
-
const asset = await (0, publish_1.handleAssetCreation)({ token: bcToken, rigobotToken: rigoToken.trim() }, courseJson, lang, deployUrl, b64IndexReadme, academyId, learnpackId, undefined, all_translations);
|
|
386
|
-
if (!asset) {
|
|
387
|
-
errors.push({
|
|
388
|
-
kind: "lang_error",
|
|
389
|
-
lang,
|
|
390
|
-
error: { detail: "Failed to create asset" },
|
|
391
|
-
});
|
|
392
|
-
console.log("No se pudo crear el asset, saltando idioma", lang);
|
|
393
|
-
continue;
|
|
394
|
-
}
|
|
395
|
-
all_translations.push(asset.slug);
|
|
396
|
-
}
|
|
397
|
-
catch (error) {
|
|
398
|
-
const errorData = error && typeof error === "object" && "response" in error ?
|
|
399
|
-
((_a = error.response) === null || _a === void 0 ? void 0 : _a.data) || error :
|
|
400
|
-
error;
|
|
401
|
-
errors.push({
|
|
402
|
-
kind: "lang_error",
|
|
403
|
-
lang,
|
|
404
|
-
error: { detail: assetSyncErrorDetail(errorData) },
|
|
405
|
-
});
|
|
406
|
-
console.error(`Error creating asset for language ${lang}:`, error);
|
|
333
|
+
return "";
|
|
407
334
|
}
|
|
335
|
+
};
|
|
336
|
+
const result = await (0, assetSync_1.syncPackageAssets)({
|
|
337
|
+
bcToken,
|
|
338
|
+
rigoToken,
|
|
339
|
+
packageSlug: courseSlug,
|
|
340
|
+
learnJson: courseJson,
|
|
341
|
+
deployUrl,
|
|
342
|
+
academyId,
|
|
343
|
+
readReadme,
|
|
344
|
+
});
|
|
345
|
+
for (const warning of result.warnings)
|
|
346
|
+
console.warn("[assets]", warning);
|
|
347
|
+
for (const synced of result.synced) {
|
|
348
|
+
console.log(`[assets] ${synced.action} "${synced.lang}": #${synced.asset.id} ${synced.asset.slug}`);
|
|
408
349
|
}
|
|
409
|
-
return { errors };
|
|
350
|
+
return { errors: result.errors };
|
|
410
351
|
};
|
|
411
352
|
const lessonCleaner = (lesson) => {
|
|
412
353
|
return Object.assign(Object.assign({}, lesson), { duration: undefined, generated: undefined, status: undefined, translations: undefined, uid: undefined, initialContent: undefined, locked: undefined });
|
|
@@ -3713,52 +3654,47 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
3713
3654
|
error: "Authentication failed, missing breathecode token",
|
|
3714
3655
|
});
|
|
3715
3656
|
}
|
|
3657
|
+
// Older IDEs only send the Breathecode token; without the Rigobot
|
|
3658
|
+
// token the lookup falls back to the title-derived slugs.
|
|
3659
|
+
const rigoToken = req.header("x-rigo-token");
|
|
3716
3660
|
const configFile = await bucket.file(`courses/${slug}/.learn/config.json`);
|
|
3717
3661
|
const [configContent] = await configFile.download();
|
|
3718
3662
|
const configJson = JSON.parse(configContent.toString());
|
|
3719
3663
|
const { config } = configJson;
|
|
3720
|
-
const
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3664
|
+
const resolution = await (0, assetResolver_1.resolvePackageAssets)({
|
|
3665
|
+
bcToken,
|
|
3666
|
+
rigoToken,
|
|
3667
|
+
packageSlug: slug,
|
|
3668
|
+
learnJson: config,
|
|
3669
|
+
});
|
|
3670
|
+
for (const warning of resolution.warnings) {
|
|
3671
|
+
console.warn("[package-academy]", warning);
|
|
3672
|
+
}
|
|
3673
|
+
const isPublished = (0, assetResolver_1.hasPublishedAsset)(resolution);
|
|
3674
|
+
const academyMode = (0, assetResolver_1.determineAcademyMode)(resolution);
|
|
3675
|
+
const warnings = [...resolution.warnings];
|
|
3676
|
+
if (resolution.packageState === "unknown") {
|
|
3677
|
+
warnings.push(`${resolution.packageError}; existing assets could not be checked.`);
|
|
3678
|
+
}
|
|
3679
|
+
for (const [lang, entry] of resolution.byLang) {
|
|
3680
|
+
if (entry.status === "unknown") {
|
|
3681
|
+
warnings.push(`"${lang}": ${entry.error}`);
|
|
3682
|
+
}
|
|
3683
|
+
else if (entry.status === "ambiguous") {
|
|
3684
|
+
warnings.push(`"${lang}": ${entry.candidates.length} assets found (${entry.candidates
|
|
3685
|
+
.map(c => `#${c.id} ${c.slug}`)
|
|
3686
|
+
.join(", ")})`);
|
|
3740
3687
|
}
|
|
3741
3688
|
}
|
|
3742
|
-
const
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
let conflictAcademies;
|
|
3746
|
-
if (uniqueAcademies.length === 0) {
|
|
3747
|
-
mode = "select";
|
|
3748
|
-
}
|
|
3749
|
-
else if (uniqueAcademies.length === 1) {
|
|
3750
|
-
mode = "locked";
|
|
3751
|
-
lockedAcademyId = uniqueAcademies[0];
|
|
3752
|
-
}
|
|
3753
|
-
else {
|
|
3754
|
-
mode = "conflict";
|
|
3755
|
-
conflictAcademies = uniqueAcademies;
|
|
3756
|
-
}
|
|
3689
|
+
const mode = academyMode.type;
|
|
3690
|
+
const lockedAcademyId = academyMode.type === "locked" ? academyMode.academyId : undefined;
|
|
3691
|
+
const conflictAcademies = academyMode.type === "conflict" ? academyMode.academies : undefined;
|
|
3757
3692
|
return res.json({
|
|
3758
3693
|
isPublished,
|
|
3759
3694
|
mode,
|
|
3760
3695
|
lockedAcademyId,
|
|
3761
3696
|
conflictAcademies,
|
|
3697
|
+
warnings,
|
|
3762
3698
|
});
|
|
3763
3699
|
}
|
|
3764
3700
|
catch (error) {
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
--color-blue-50: oklch(97% 0.014 254.604);
|
|
66
66
|
--color-blue-100: oklch(93.2% 0.032 255.585);
|
|
67
67
|
--color-blue-200: oklch(88.2% 0.059 254.128);
|
|
68
|
+
--color-blue-300: oklch(80.9% 0.105 251.813);
|
|
68
69
|
--color-blue-400: oklch(70.7% 0.165 254.624);
|
|
69
70
|
--color-blue-500: oklch(62.3% 0.214 259.815);
|
|
70
71
|
--color-blue-600: oklch(54.6% 0.245 262.881);
|
|
@@ -439,6 +440,12 @@
|
|
|
439
440
|
.z-1000 {
|
|
440
441
|
z-index: 1000;
|
|
441
442
|
}
|
|
443
|
+
.col-span-2 {
|
|
444
|
+
grid-column: span 2 / span 2;
|
|
445
|
+
}
|
|
446
|
+
.row-start-2 {
|
|
447
|
+
grid-row-start: 2;
|
|
448
|
+
}
|
|
442
449
|
.container {
|
|
443
450
|
width: 100%;
|
|
444
451
|
}
|
|
@@ -536,6 +543,9 @@
|
|
|
536
543
|
.flex {
|
|
537
544
|
display: flex;
|
|
538
545
|
}
|
|
546
|
+
.grid {
|
|
547
|
+
display: grid;
|
|
548
|
+
}
|
|
539
549
|
.hidden {
|
|
540
550
|
display: none;
|
|
541
551
|
}
|
|
@@ -548,6 +558,9 @@
|
|
|
548
558
|
.table {
|
|
549
559
|
display: table;
|
|
550
560
|
}
|
|
561
|
+
.field-sizing-content {
|
|
562
|
+
field-sizing: content;
|
|
563
|
+
}
|
|
551
564
|
.h-2 {
|
|
552
565
|
height: calc(var(--spacing) * 2);
|
|
553
566
|
}
|
|
@@ -644,6 +657,9 @@
|
|
|
644
657
|
.w-full {
|
|
645
658
|
width: 100%;
|
|
646
659
|
}
|
|
660
|
+
.max-w-64 {
|
|
661
|
+
max-width: calc(var(--spacing) * 64);
|
|
662
|
+
}
|
|
647
663
|
.max-w-\[700px\] {
|
|
648
664
|
max-width: 700px;
|
|
649
665
|
}
|
|
@@ -705,6 +721,9 @@
|
|
|
705
721
|
.list-disc {
|
|
706
722
|
list-style-type: disc;
|
|
707
723
|
}
|
|
724
|
+
.grid-cols-2 {
|
|
725
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
726
|
+
}
|
|
708
727
|
.flex-col {
|
|
709
728
|
flex-direction: column;
|
|
710
729
|
}
|
|
@@ -780,6 +799,15 @@
|
|
|
780
799
|
calc(var(--spacing) * 2) * calc(1 - var(--tw-space-x-reverse))
|
|
781
800
|
);
|
|
782
801
|
}
|
|
802
|
+
.justify-self-center {
|
|
803
|
+
justify-self: center;
|
|
804
|
+
}
|
|
805
|
+
.justify-self-end {
|
|
806
|
+
justify-self: flex-end;
|
|
807
|
+
}
|
|
808
|
+
.justify-self-start {
|
|
809
|
+
justify-self: flex-start;
|
|
810
|
+
}
|
|
783
811
|
.truncate {
|
|
784
812
|
text-overflow: ellipsis;
|
|
785
813
|
white-space: nowrap;
|
|
@@ -905,6 +933,9 @@
|
|
|
905
933
|
.bg-red-100 {
|
|
906
934
|
background-color: var(--color-red-100);
|
|
907
935
|
}
|
|
936
|
+
.bg-transparent {
|
|
937
|
+
background-color: #0000;
|
|
938
|
+
}
|
|
908
939
|
.bg-white {
|
|
909
940
|
background-color: var(--color-white);
|
|
910
941
|
}
|
|
@@ -1046,6 +1077,9 @@
|
|
|
1046
1077
|
.break-words {
|
|
1047
1078
|
overflow-wrap: break-word;
|
|
1048
1079
|
}
|
|
1080
|
+
.whitespace-nowrap {
|
|
1081
|
+
white-space: nowrap;
|
|
1082
|
+
}
|
|
1049
1083
|
.whitespace-pre-line {
|
|
1050
1084
|
white-space: pre-line;
|
|
1051
1085
|
}
|
|
@@ -1244,6 +1278,19 @@
|
|
|
1244
1278
|
.focus\:ring-blue-200:focus {
|
|
1245
1279
|
--tw-ring-color: var(--color-blue-200);
|
|
1246
1280
|
}
|
|
1281
|
+
.focus\:outline-none:focus {
|
|
1282
|
+
--tw-outline-style: none;
|
|
1283
|
+
outline-style: none;
|
|
1284
|
+
}
|
|
1285
|
+
.focus-visible\:ring-2:focus-visible {
|
|
1286
|
+
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0
|
|
1287
|
+
calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
|
1288
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow),
|
|
1289
|
+
var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1290
|
+
}
|
|
1291
|
+
.focus-visible\:ring-blue-300:focus-visible {
|
|
1292
|
+
--tw-ring-color: var(--color-blue-300);
|
|
1293
|
+
}
|
|
1247
1294
|
.disabled\:cursor-not-allowed:disabled {
|
|
1248
1295
|
cursor: not-allowed;
|
|
1249
1296
|
}
|
|
@@ -1257,9 +1304,21 @@
|
|
|
1257
1304
|
opacity: 0.5;
|
|
1258
1305
|
}
|
|
1259
1306
|
@media (min-width: 40rem) {
|
|
1307
|
+
.sm\:col-span-1 {
|
|
1308
|
+
grid-column: span 1 / span 1;
|
|
1309
|
+
}
|
|
1310
|
+
.sm\:col-start-2 {
|
|
1311
|
+
grid-column-start: 2;
|
|
1312
|
+
}
|
|
1313
|
+
.sm\:row-start-1 {
|
|
1314
|
+
grid-row-start: 1;
|
|
1315
|
+
}
|
|
1260
1316
|
.sm\:w-auto {
|
|
1261
1317
|
width: auto;
|
|
1262
1318
|
}
|
|
1319
|
+
.sm\:grid-cols-\[1fr_auto_1fr\] {
|
|
1320
|
+
grid-template-columns: 1fr auto 1fr;
|
|
1321
|
+
}
|
|
1263
1322
|
.sm\:flex-row {
|
|
1264
1323
|
flex-direction: row;
|
|
1265
1324
|
}
|