@burdenoff/microfe-technospam 2026.1031.1 → 2026.1031.2
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/dist/technospam/components/StatusBadge.js +1 -1
- package/dist/technospam/components/StatusBadge.js.map +1 -1
- package/dist/technospam/components/SubmissionViews.js +1 -1
- package/dist/technospam/components/SubmissionViews.js.map +1 -1
- package/dist/technospam/components/lesson/InteractiveWorkspace.js +1 -1
- package/dist/technospam/components/lesson/InteractiveWorkspace.js.map +1 -1
- package/dist/technospam/pages/AdminAdminDashboardPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js +194 -186
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
- package/dist/technospam/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js +5 -2
- package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsPortfolioPagePage.js +1 -0
- package/dist/technospam/pages/ApplicationsPortfolioPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js +2 -1
- package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js +167 -162
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +2 -2
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.js +77 -77
- package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesLessonPlayerPagePage.js +2 -2
- package/dist/technospam/pages/CoursesLessonPlayerPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js +3 -3
- package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js +71 -71
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.d.ts.map +1 -1
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js +6 -1
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.js +1 -0
- package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipSessionsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/MentorshipSessionsPagePage.js +97 -98
- package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
- package/package.json +7 -6
|
@@ -4,7 +4,7 @@ import { Badge as n } from "@burdenoff/fe-libs/ui";
|
|
|
4
4
|
//#region src/technospam/components/StatusBadge.tsx
|
|
5
5
|
var r = {
|
|
6
6
|
neutral: "bg-bg-sunken text-text-secondary border-border-seam",
|
|
7
|
-
info: "bg-accent-primary/
|
|
7
|
+
info: "bg-accent-primary/6 text-accent-primary border-accent-primary/30",
|
|
8
8
|
success: "bg-status-success-bg-subtle text-status-success-text border-status-success-border",
|
|
9
9
|
warning: "bg-status-warning-bg-subtle text-status-warning-text border-status-warning-border",
|
|
10
10
|
danger: "bg-status-error-bg-subtle text-status-error-text border-status-error-border"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBadge.js","names":[],"sources":["../../../src/technospam/components/StatusBadge.tsx"],"sourcesContent":["import { Badge } from '@burdenoff/fe-libs/ui';\nimport { humanizeEnum } from '../utils/format';\n\ntype Tone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\nconst TONE_CLASS: Record<Tone, string> = {\n neutral: 'bg-bg-sunken text-text-secondary border-border-seam',\n info: 'bg-accent-primary/
|
|
1
|
+
{"version":3,"file":"StatusBadge.js","names":[],"sources":["../../../src/technospam/components/StatusBadge.tsx"],"sourcesContent":["import { Badge } from '@burdenoff/fe-libs/ui';\nimport { humanizeEnum } from '../utils/format';\n\ntype Tone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\nconst TONE_CLASS: Record<Tone, string> = {\n neutral: 'bg-bg-sunken text-text-secondary border-border-seam',\n info: 'bg-accent-primary/6 text-accent-primary border-accent-primary/30',\n success: 'bg-status-success-bg-subtle text-status-success-text border-status-success-border',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-border',\n danger: 'bg-status-error-bg-subtle text-status-error-text border-status-error-border',\n};\n\n/** Maps any Tec* status enum to a semantic tone. Unknown values fall back to neutral. */\nconst STATUS_TONE: Record<string, Tone> = {\n // course / problem\n DRAFT: 'neutral',\n PUBLISHED: 'success',\n ARCHIVED: 'warning',\n // enrollment\n ENROLLED: 'info',\n IN_PROGRESS: 'info',\n COMPLETED: 'success',\n DROPPED: 'warning',\n // certificate\n ISSUED: 'success',\n REVOKED: 'danger',\n // submission verdict\n PENDING: 'neutral',\n ACCEPTED: 'success',\n WRONG_ANSWER: 'danger',\n TIME_LIMIT_EXCEEDED: 'warning',\n RUNTIME_ERROR: 'danger',\n COMPILE_ERROR: 'danger',\n // mentor\n ACTIVE: 'success',\n PAUSED: 'warning',\n INACTIVE: 'neutral',\n // session\n REQUESTED: 'info',\n CONFIRMED: 'success',\n CANCELLED: 'danger',\n NO_SHOW: 'danger',\n // hackathon\n REGISTRATION_OPEN: 'success',\n JUDGING: 'info',\n // team\n SUBMITTED: 'success',\n DISQUALIFIED: 'danger',\n WINNER: 'success',\n};\n\nconst DIFFICULTY_TONE: Record<string, Tone> = {\n EASY: 'success',\n MEDIUM: 'warning',\n HARD: 'danger',\n BEGINNER: 'success',\n INTERMEDIATE: 'info',\n ADVANCED: 'warning',\n EXPERT: 'danger',\n};\n\nexport function StatusBadge({\n status,\n kind = 'status',\n}: {\n status?: string | null;\n kind?: 'status' | 'level';\n}) {\n if (!status) return null;\n const tone = (kind === 'level' ? DIFFICULTY_TONE[status] : STATUS_TONE[status]) ?? 'neutral';\n return (\n <Badge variant=\"outline\" className={TONE_CLASS[tone]}>\n {humanizeEnum(status)}\n </Badge>\n );\n}\n"],"mappings":";;;;AAKA,IAAM,IAAmC;CACvC,SAAS;CACT,MAAM;CACN,SAAS;CACT,SAAS;CACT,QAAQ;CACT,EAGK,IAAoC;CAExC,OAAO;CACP,WAAW;CACX,UAAU;CAEV,UAAU;CACV,aAAa;CACb,WAAW;CACX,SAAS;CAET,QAAQ;CACR,SAAS;CAET,SAAS;CACT,UAAU;CACV,cAAc;CACd,qBAAqB;CACrB,eAAe;CACf,eAAe;CAEf,QAAQ;CACR,QAAQ;CACR,UAAU;CAEV,WAAW;CACX,WAAW;CACX,WAAW;CACX,SAAS;CAET,mBAAmB;CACnB,SAAS;CAET,WAAW;CACX,cAAc;CACd,QAAQ;CACT,EAEK,IAAwC;CAC5C,MAAM;CACN,QAAQ;CACR,MAAM;CACN,UAAU;CACV,cAAc;CACd,UAAU;CACV,QAAQ;CACT;AAED,SAAgB,EAAY,EAC1B,WACA,UAAO,YAIN;AAGD,QAFK,IAGH,kBAAC,GAAD;EAAO,SAAQ;EAAU,WAAW,GAFxB,MAAS,UAAU,EAAgB,KAAU,EAAY,OAAY;YAG9E,EAAa,EAAO;EACf,CAAA,GALU"}
|
|
@@ -18,7 +18,7 @@ function f({ label: t, children: n, bodyClassName: r }) {
|
|
|
18
18
|
/* @__PURE__ */ l("span", { className: "h-2.5 w-2.5 rounded-full bg-status-success-border" })
|
|
19
19
|
]
|
|
20
20
|
}), /* @__PURE__ */ u("span", {
|
|
21
|
-
className: "inline-flex items-center gap-1.5 font-mono text-xs text-text-
|
|
21
|
+
className: "inline-flex items-center gap-1.5 font-mono text-xs text-text-secondary",
|
|
22
22
|
children: [
|
|
23
23
|
/* @__PURE__ */ l(a, { size: 13 }),
|
|
24
24
|
" ",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubmissionViews.js","names":[],"sources":["../../../src/technospam/components/SubmissionViews.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { CheckCircle2, Clock, Code2, EyeOff, MinusCircle, XCircle } from 'lucide-react';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from './StatusBadge';\nimport { humanizeEnum } from '../utils/format';\nimport { cn } from '../utils/cn';\nimport type { TecSubmission, TecTestCaseStatus } from '../api/technospamApi';\n\n/**\n * A dark, editor-window styled code surface: mac-style traffic-light dots plus a\n * language label header over a scrollable monospace body so read-only code reads\n * like a real IDE panel rather than a flat block.\n */\nexport function CodePanel({\n label,\n children,\n bodyClassName,\n}: {\n label: string;\n children: ReactNode;\n bodyClassName?: string;\n}) {\n return (\n <div className=\"overflow-hidden rounded-xl border border-border-strong bg-bg-sunken shadow-sm\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border-seam bg-bg-canvas/40 px-4 py-2\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-error-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-warning-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-success-border\" />\n </div>\n <span className=\"inline-flex items-center gap-1.5 font-mono text-xs text-text-
|
|
1
|
+
{"version":3,"file":"SubmissionViews.js","names":[],"sources":["../../../src/technospam/components/SubmissionViews.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { CheckCircle2, Clock, Code2, EyeOff, MinusCircle, XCircle } from 'lucide-react';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from './StatusBadge';\nimport { humanizeEnum } from '../utils/format';\nimport { cn } from '../utils/cn';\nimport type { TecSubmission, TecTestCaseStatus } from '../api/technospamApi';\n\n/**\n * A dark, editor-window styled code surface: mac-style traffic-light dots plus a\n * language label header over a scrollable monospace body so read-only code reads\n * like a real IDE panel rather than a flat block.\n */\nexport function CodePanel({\n label,\n children,\n bodyClassName,\n}: {\n label: string;\n children: ReactNode;\n bodyClassName?: string;\n}) {\n return (\n <div className=\"overflow-hidden rounded-xl border border-border-strong bg-bg-sunken shadow-sm\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border-seam bg-bg-canvas/40 px-4 py-2\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-error-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-warning-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-success-border\" />\n </div>\n <span className=\"inline-flex items-center gap-1.5 font-mono text-xs text-text-secondary\">\n <Code2 size={13} /> {label}\n </span>\n </div>\n <pre\n className={cn(\n 'overflow-auto p-4 font-mono text-xs leading-relaxed text-text-primary',\n bodyClassName\n )}\n >\n {children}\n </pre>\n </div>\n );\n}\n\n/** One labelled monospace input/output block inside a test-case result. */\nexport function IoBlock({ label, value }: { label: string; value?: string | null }) {\n return (\n <div className=\"min-w-0\">\n <p className=\"mb-1 text-xs font-medium uppercase tracking-wide text-text-muted\">{label}</p>\n <pre className=\"overflow-auto rounded-lg bg-bg-sunken px-3 py-2 font-mono text-xs leading-relaxed text-text-primary\">\n {value?.length ? value : '—'}\n </pre>\n </div>\n );\n}\n\n/** Icon + tone for a per-test-case status, using semantic tokens only. */\nfunction testCaseStatusTone(status: TecTestCaseStatus): { icon: ReactNode; className: string } {\n if (status === 'PASSED') {\n return { icon: <CheckCircle2 size={14} />, className: 'text-status-success-fg' };\n }\n if (status === 'SKIPPED') {\n return { icon: <MinusCircle size={14} />, className: 'text-text-muted' };\n }\n return { icon: <XCircle size={14} />, className: 'text-status-error-fg' };\n}\n\n/**\n * Per-test-case grading detail for a graded submission — shared by the learner's\n * problem page and the authoring console's grading panel.\n *\n * The backend redacts HIDDEN fixtures before persisting results, so a hidden\n * row here only ever carries its name and status — never the input, the\n * expected output, or what the submitted program actually printed.\n */\nexport function TestResultsPanel({\n submission,\n actualOutputLabel = 'Your output',\n}: {\n submission: TecSubmission;\n actualOutputLabel?: string;\n}) {\n const results = submission.testResults ?? [];\n if (results.length === 0) return null;\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1\">\n <StatusBadge status={submission.verdict} />\n <span className=\"text-sm text-text-secondary\">\n Passed {submission.passedCount} of {submission.totalCount} test cases\n </span>\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Clock size={12} /> {submission.runtimeMs} ms\n </span>\n </div>\n\n <div className=\"divide-y divide-border-seam overflow-hidden rounded-xl border border-border-seam\">\n {results.map((result) => {\n const tone = testCaseStatusTone(result.status);\n return (\n <div key={result.testCaseId} className=\"space-y-2 bg-bg-surface px-4 py-3\">\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1\">\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 text-sm font-medium',\n tone.className\n )}\n >\n {tone.icon} {result.name}\n </span>\n <Badge variant=\"outline\">{humanizeEnum(result.status)}</Badge>\n {result.visibility === 'HIDDEN' ? (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <EyeOff size={12} /> hidden test\n </span>\n ) : null}\n <span className=\"ml-auto text-xs text-text-muted\">{result.durationMs} ms</span>\n </div>\n\n {result.visibility === 'PUBLIC' && result.status !== 'SKIPPED' ? (\n <div className=\"grid grid-cols-1 gap-2 sm:grid-cols-3\">\n <IoBlock label=\"Input\" value={result.input} />\n <IoBlock label=\"Expected\" value={result.expectedOutput} />\n <IoBlock label={actualOutputLabel} value={result.actualOutput} />\n </div>\n ) : null}\n </div>\n );\n })}\n </div>\n\n {submission.stderr ? (\n <CodePanel label=\"stderr\" bodyClassName=\"max-h-48\">\n {submission.stderr}\n </CodePanel>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,EAAU,EACxB,UACA,aACA,oBAKC;AACD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,QAAD,EAAM,WAAU,mDAAoD,CAAA;KACpE,kBAAC,QAAD,EAAM,WAAU,qDAAsD,CAAA;KACtE,kBAAC,QAAD,EAAM,WAAU,qDAAsD,CAAA;KAClE;OACN,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;KAAE;KAChB;MACH;MACN,kBAAC,OAAD;GACE,WAAW,EACT,yEACA,EACD;GAEA;GACG,CAAA,CACF;;;AAKV,SAAgB,EAAQ,EAAE,UAAO,YAAmD;AAClF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,KAAD;GAAG,WAAU;aAAoE;GAAU,CAAA,EAC3F,kBAAC,OAAD;GAAK,WAAU;aACZ,GAAO,SAAS,IAAQ;GACrB,CAAA,CACF;;;AAKV,SAAS,EAAmB,GAAmE;AAO7F,QANI,MAAW,WACN;EAAE,MAAM,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA;EAAE,WAAW;EAA0B,GAE9E,MAAW,YACN;EAAE,MAAM,kBAAC,GAAD,EAAa,MAAM,IAAM,CAAA;EAAE,WAAW;EAAmB,GAEnE;EAAE,MAAM,kBAAC,GAAD,EAAS,MAAM,IAAM,CAAA;EAAE,WAAW;EAAwB;;AAW3E,SAAgB,EAAiB,EAC/B,eACA,uBAAoB,iBAInB;CACD,IAAM,IAAU,EAAW,eAAe,EAAE;AAG5C,QAFI,EAAQ,WAAW,IAAU,OAG/B,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAa,QAAQ,EAAW,SAAW,CAAA;KAC3C,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OAA8C;OACpC,EAAW;OAAY;OAAK,EAAW;OAAW;OACrD;;KACP,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;OAAE,EAAW;OAAU;OACrC;;KACH;;GAEN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAQ,KAAK,MAAW;KACvB,IAAM,IAAO,EAAmB,EAAO,OAAO;AAC9C,YACE,kBAAC,OAAD;MAA6B,WAAU;gBAAvC,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,QAAD;SACE,WAAW,EACT,wDACA,EAAK,UACN;mBAJH;UAMG,EAAK;UAAK;UAAE,EAAO;UACf;;QACP,kBAAC,GAAD;SAAO,SAAQ;mBAAW,EAAa,EAAO,OAAO;SAAS,CAAA;QAC7D,EAAO,eAAe,WACrB,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CACE,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA,EAAA,eACf;aACL;QACJ,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CAAmD,EAAO,YAAW,MAAU;;QAC3E;UAEL,EAAO,eAAe,YAAY,EAAO,WAAW,YACnD,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD;SAAS,OAAM;SAAQ,OAAO,EAAO;SAAS,CAAA;QAC9C,kBAAC,GAAD;SAAS,OAAM;SAAW,OAAO,EAAO;SAAkB,CAAA;QAC1D,kBAAC,GAAD;SAAS,OAAO;SAAmB,OAAO,EAAO;SAAgB,CAAA;QAC7D;WACJ,KACA;QA1BI,EAAO,WA0BX;MAER;IACE,CAAA;GAEL,EAAW,SACV,kBAAC,GAAD;IAAW,OAAM;IAAS,eAAc;cACrC,EAAW;IACF,CAAA,GACV;GACA"}
|
|
@@ -82,7 +82,7 @@ function C({ lesson: C, onCompleted: w }) {
|
|
|
82
82
|
/* @__PURE__ */ g("span", { className: "h-2.5 w-2.5 rounded-full bg-status-success-border" })
|
|
83
83
|
]
|
|
84
84
|
}), /* @__PURE__ */ _("span", {
|
|
85
|
-
className: "inline-flex items-center gap-1.5 font-mono text-xs text-text-
|
|
85
|
+
className: "inline-flex items-center gap-1.5 font-mono text-xs text-text-secondary",
|
|
86
86
|
children: [
|
|
87
87
|
/* @__PURE__ */ g(u, { size: 13 }),
|
|
88
88
|
" ",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InteractiveWorkspace.js","names":[],"sources":["../../../../src/technospam/components/lesson/InteractiveWorkspace.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport {\n CheckCircle2,\n Clock,\n Code2,\n Loader2,\n Play,\n RotateCcw,\n Terminal,\n XCircle,\n} from 'lucide-react';\nimport { Button, Textarea } from '@burdenoff/fe-libs/ui';\nimport { IoBlock } from '../SubmissionViews';\nimport { humanizeEnum } from '../../utils/format';\nimport { cn } from '../../utils/cn';\nimport { userMessageFromError } from '../../lib/errorMessage';\nimport { useRunLessonCode, type TecLesson, type TecLessonCodeRun } from '../../api/technospamApi';\n\n/**\n * A cold code sandbox can take up to a few minutes to start. While the API\n * answers WARMING we call it again on this interval, giving up after the\n * budget below so the learner can retry by hand.\n */\nconst WARMING_RETRY_MS = 4_000;\nconst WARMING_BUDGET_MS = 4 * 60_000;\n\nfunction runSummary(run: TecLessonCodeRun): {\n tone: 'success' | 'error' | 'neutral';\n text: string;\n} {\n if (run.compileFailed) return { tone: 'error', text: 'Compile error' };\n if (run.timedOut) return { tone: 'error', text: 'Time limit exceeded' };\n if (run.memoryLimitExceeded) return { tone: 'error', text: 'Memory limit exceeded' };\n if (run.exitCode !== 0) return { tone: 'error', text: `Exited with code ${run.exitCode}` };\n if (run.matchedExpected === true)\n return { tone: 'success', text: 'Output matches the expected output' };\n if (run.matchedExpected === false) return { tone: 'error', text: 'Output does not match yet' };\n return { tone: 'neutral', text: 'Ran successfully' };\n}\n\n/**\n * Runnable workspace for an INTERACTIVE lesson (BOFF-4107). Mount it with\n * `key={lesson.id}` so moving to another lesson starts a fresh editor: an editor\n * pre-filled with the lesson's starter code, an optional stdin box, and the\n * run output. Code runs only in the platform sandbox via `tecRunLessonCode`;\n * when the lesson has an expected output, a matching run completes the lesson\n * server-side and `onCompleted` lets the page refresh progress.\n */\nexport function InteractiveWorkspace({\n lesson,\n onCompleted,\n}: {\n lesson: TecLesson;\n onCompleted: () => void;\n}) {\n const starter = lesson.starterCode ?? '';\n const [code, setCode] = useState(starter);\n const [stdin, setStdin] = useState(lesson.sampleInput ?? '');\n const [run, setRun] = useState<TecLessonCodeRun | null>(null);\n const [warming, setWarming] = useState(false);\n const [running, setRunning] = useState(false);\n /** Why the last run was refused (for example a spent sandbox quota), shown inline. */\n const [runError, setRunError] = useState<string | null>(null);\n const warmingSince = useRef<number | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const [runLessonCode] = useRunLessonCode();\n\n // The page mounts one workspace per lesson (keyed by lesson id), so the\n // editor starts fresh on every lesson; only the pending retry needs cleanup.\n useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current);\n },\n []\n );\n\n const execute = async (): Promise<void> => {\n setRunning(true);\n setRunError(null);\n try {\n const res = await runLessonCode({\n variables: {\n input: {\n lessonId: lesson.id,\n language: lesson.language ?? undefined,\n code,\n stdin,\n },\n },\n });\n const result = res.data?.tecRunLessonCode;\n if (!result) {\n // The mutation failed (for example a spent sandbox quota). Stop any\n // warm-up polling, re-enable Run and say why next to the editor, where\n // the learner is looking, not only in a transient toast.\n setWarming(false);\n warmingSince.current = null;\n setRun(null);\n setRunError(\n userMessageFromError(res.error, 'Your code could not be run. Please try again.')\n );\n return;\n }\n if (result.status === 'WARMING') {\n warmingSince.current ??= Date.now();\n if (Date.now() - warmingSince.current < WARMING_BUDGET_MS) {\n setWarming(true);\n timer.current = setTimeout(() => void execute(), WARMING_RETRY_MS);\n return;\n }\n setWarming(false);\n warmingSince.current = null;\n setRun({ ...result, status: 'UNAVAILABLE' });\n return;\n }\n setWarming(false);\n warmingSince.current = null;\n setRun(result);\n if (result.lessonCompleted) onCompleted();\n } finally {\n setRunning(false);\n }\n };\n\n const busy = running || warming;\n const summary = run && run.status === 'COMPLETED' ? runSummary(run) : null;\n\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-hidden rounded-xl border border-border-strong bg-bg-sunken shadow-sm\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border-seam bg-bg-canvas/40 px-4 py-2\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-error-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-warning-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-success-border\" />\n </div>\n <span className=\"inline-flex items-center gap-1.5 font-mono text-xs text-text-muted\">\n <Code2 size={13} /> {lesson.language ? humanizeEnum(lesson.language) : 'code'}\n </span>\n </div>\n <Textarea\n aria-label=\"Lesson code editor\"\n value={code}\n onChange={(e) => setCode(e.target.value)}\n placeholder=\"Write your code…\"\n className=\"min-h-[260px] resize-y rounded-none border-0 bg-transparent font-mono text-xs leading-relaxed focus-visible:ring-0 focus-visible:ring-offset-0\"\n spellCheck={false}\n />\n </div>\n\n <div>\n <label\n htmlFor={`tec-lesson-stdin-${lesson.id}`}\n className=\"mb-1 block text-xs font-medium uppercase tracking-wide text-text-muted\"\n >\n Input (stdin)\n </label>\n <Textarea\n id={`tec-lesson-stdin-${lesson.id}`}\n value={stdin}\n onChange={(e) => setStdin(e.target.value)}\n placeholder=\"Optional input your program reads\"\n className=\"min-h-[64px] font-mono text-xs\"\n spellCheck={false}\n />\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button onClick={() => void execute()} disabled={busy || !code.trim()}>\n {busy ? <Loader2 size={16} className=\"animate-spin\" /> : <Play size={16} />}\n {warming ? 'Starting sandbox…' : running ? 'Running…' : 'Run code'}\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => {\n setCode(starter);\n setRun(null);\n setRunError(null);\n }}\n disabled={busy || code === starter}\n >\n <RotateCcw size={15} /> Reset to starter\n </Button>\n <span className=\"text-xs text-text-muted\">Runs in an isolated sandbox.</span>\n </div>\n\n {warming ? (\n <p\n role=\"status\"\n className=\"rounded-lg border border-border-seam bg-bg-sunken px-3 py-2 text-sm text-text-secondary\"\n >\n The code sandbox is starting up. Your code will run automatically as soon as it is ready.\n </p>\n ) : null}\n\n {runError ? (\n <p\n role=\"alert\"\n data-testid=\"lesson-run-error\"\n className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\"\n >\n {runError}\n </p>\n ) : null}\n\n {run?.status === 'UNAVAILABLE' ? (\n <p\n role=\"alert\"\n className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\"\n >\n The code sandbox is not available right now. Please try again in a moment.\n </p>\n ) : null}\n\n {run && summary ? (\n <div\n className=\"space-y-3 rounded-xl border border-border-seam p-4\"\n data-testid=\"lesson-run-output\"\n >\n <div className=\"flex flex-wrap items-center gap-3\">\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 text-sm font-medium',\n summary.tone === 'success' && 'text-status-success-text',\n summary.tone === 'error' && 'text-status-error-text',\n summary.tone === 'neutral' && 'text-text-primary'\n )}\n >\n {summary.tone === 'error' ? <XCircle size={16} /> : <CheckCircle2 size={16} />}\n {summary.text}\n </span>\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Clock size={12} /> {run.durationMs} ms\n </span>\n {run.lessonCompleted ? (\n <span className=\"rounded-full border border-status-success-border bg-status-success-bg-subtle px-2 py-0.5 text-xs font-medium text-status-success-text\">\n Lesson completed\n </span>\n ) : null}\n </div>\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <IoBlock label=\"Output\" value={run.stdout} />\n {lesson.expectedOutput ? (\n <IoBlock label=\"Expected output\" value={lesson.expectedOutput} />\n ) : null}\n </div>\n {run.stderr ? (\n <div>\n <p className=\"mb-1 flex items-center gap-1 text-xs font-medium uppercase tracking-wide text-text-muted\">\n <Terminal size={12} /> Errors\n </p>\n <pre className=\"overflow-auto rounded-lg bg-status-error-bg-subtle px-3 py-2 font-mono text-xs text-status-error-text\">\n {run.stderr}\n </pre>\n </div>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAuBA,IAAM,IAAmB,KACnB,IAAoB,IAAI;AAE9B,SAAS,EAAW,GAGlB;AAQA,QAPI,EAAI,gBAAsB;EAAE,MAAM;EAAS,MAAM;EAAiB,GAClE,EAAI,WAAiB;EAAE,MAAM;EAAS,MAAM;EAAuB,GACnE,EAAI,sBAA4B;EAAE,MAAM;EAAS,MAAM;EAAyB,GAChF,EAAI,aAAa,IACjB,EAAI,oBAAoB,KACnB;EAAE,MAAM;EAAW,MAAM;EAAsC,GACpE,EAAI,oBAAoB,KAAc;EAAE,MAAM;EAAS,MAAM;EAA6B,GACvF;EAAE,MAAM;EAAW,MAAM;EAAoB,GAJrB;EAAE,MAAM;EAAS,MAAM,oBAAoB,EAAI;EAAY;;AAe5F,SAAgB,EAAqB,EACnC,WACA,kBAIC;CACD,IAAM,IAAU,EAAO,eAAe,IAChC,CAAC,GAAM,KAAW,EAAS,EAAQ,EACnC,CAAC,GAAO,KAAY,EAAS,EAAO,eAAe,GAAG,EACtD,CAAC,GAAK,KAAU,EAAkC,KAAK,EACvD,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAS,KAAc,EAAS,GAAM,EAEvC,CAAC,GAAU,KAAe,EAAwB,KAAK,EACvD,IAAe,EAAsB,KAAK,EAC1C,IAAQ,EAA6C,KAAK,EAC1D,CAAC,KAAiB,GAAkB;AAI1C,eACc;AACV,EAAI,EAAM,WAAS,aAAa,EAAM,QAAQ;IAEhD,EAAE,CACH;CAED,IAAM,IAAU,YAA2B;AAEzC,EADA,EAAW,GAAK,EAChB,EAAY,KAAK;AACjB,MAAI;GACF,IAAM,IAAM,MAAM,EAAc,EAC9B,WAAW,EACT,OAAO;IACL,UAAU,EAAO;IACjB,UAAU,EAAO,YAAY,KAAA;IAC7B;IACA;IACD,EACF,EACF,CAAC,EACI,IAAS,EAAI,MAAM;AACzB,OAAI,CAAC,GAAQ;AAOX,IAHA,EAAW,GAAM,EACjB,EAAa,UAAU,MACvB,EAAO,KAAK,EACZ,EACE,EAAqB,EAAI,OAAO,gDAAgD,CACjF;AACD;;AAEF,OAAI,EAAO,WAAW,WAAW;AAE/B,QADA,EAAa,YAAY,KAAK,KAAK,EAC/B,KAAK,KAAK,GAAG,EAAa,UAAU,GAAmB;AAEzD,KADA,EAAW,GAAK,EAChB,EAAM,UAAU,iBAAiB,KAAK,GAAS,EAAE,EAAiB;AAClE;;AAIF,IAFA,EAAW,GAAM,EACjB,EAAa,UAAU,MACvB,EAAO;KAAE,GAAG;KAAQ,QAAQ;KAAe,CAAC;AAC5C;;AAKF,GAHA,EAAW,GAAM,EACjB,EAAa,UAAU,MACvB,EAAO,EAAO,EACV,EAAO,mBAAiB,GAAa;YACjC;AACR,KAAW,GAAM;;IAIf,IAAO,KAAW,GAClB,IAAU,KAAO,EAAI,WAAW,cAAc,EAAW,EAAI,GAAG;AAEtE,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,QAAD,EAAM,WAAU,mDAAoD,CAAA;OACpE,kBAAC,QAAD,EAAM,WAAU,qDAAsD,CAAA;OACtE,kBAAC,QAAD,EAAM,WAAU,qDAAsD,CAAA;OAClE;SACN,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;OAAE,EAAO,WAAW,EAAa,EAAO,SAAS,GAAG;OAClE;QACH;QACN,kBAAC,GAAD;KACE,cAAW;KACX,OAAO;KACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;KACxC,aAAY;KACZ,WAAU;KACV,YAAY;KACZ,CAAA,CACE;;GAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IACE,SAAS,oBAAoB,EAAO;IACpC,WAAU;cACX;IAEO,CAAA,EACR,kBAAC,GAAD;IACE,IAAI,oBAAoB,EAAO;IAC/B,OAAO;IACP,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;IACzC,aAAY;IACZ,WAAU;IACV,YAAY;IACZ,CAAA,CACE,EAAA,CAAA;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAQ,eAAe,KAAK,GAAS;MAAE,UAAU,KAAQ,CAAC,EAAK,MAAM;gBAArE,CACG,IAAO,kBAAC,GAAD;OAAS,MAAM;OAAI,WAAU;OAAiB,CAAA,GAAG,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EAC1E,IAAU,sBAAsB,IAAU,aAAa,WACjD;;KACT,kBAAC,GAAD;MACE,SAAQ;MACR,eAAe;AAGb,OAFA,EAAQ,EAAQ,EAChB,EAAO,KAAK,EACZ,EAAY,KAAK;;MAEnB,UAAU,KAAQ,MAAS;gBAP7B,CASE,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA,EAAA,oBAChB;;KACT,kBAAC,QAAD;MAAM,WAAU;gBAA0B;MAAmC,CAAA;KACzE;;GAEL,IACC,kBAAC,KAAD;IACE,MAAK;IACL,WAAU;cACX;IAEG,CAAA,GACF;GAEH,IACC,kBAAC,KAAD;IACE,MAAK;IACL,eAAY;IACZ,WAAU;cAET;IACC,CAAA,GACF;GAEH,GAAK,WAAW,gBACf,kBAAC,KAAD;IACE,MAAK;IACL,WAAU;cACX;IAEG,CAAA,GACF;GAEH,KAAO,IACN,kBAAC,OAAD;IACE,WAAU;IACV,eAAY;cAFd;KAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,QAAD;QACE,WAAW,EACT,wDACA,EAAQ,SAAS,aAAa,4BAC9B,EAAQ,SAAS,WAAW,0BAC5B,EAAQ,SAAS,aAAa,oBAC/B;kBANH,CAQG,EAAQ,SAAS,UAAU,kBAAC,GAAD,EAAS,MAAM,IAAM,CAAA,GAAG,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA,EAC7E,EAAQ,KACJ;;OACP,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;SAAE,EAAI;SAAW;SAC/B;;OACN,EAAI,kBACH,kBAAC,QAAD;QAAM,WAAU;kBAAwI;QAEjJ,CAAA,GACL;OACA;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAS,OAAM;OAAS,OAAO,EAAI;OAAU,CAAA,EAC5C,EAAO,iBACN,kBAAC,GAAD;OAAS,OAAM;OAAkB,OAAO,EAAO;OAAkB,CAAA,GAC/D,KACA;;KACL,EAAI,SACH,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAb,CACE,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA,EAAA,UACpB;SACJ,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAI;MACD,CAAA,CACF,EAAA,CAAA,GACJ;KACA;QACJ;GACA"}
|
|
1
|
+
{"version":3,"file":"InteractiveWorkspace.js","names":[],"sources":["../../../../src/technospam/components/lesson/InteractiveWorkspace.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport {\n CheckCircle2,\n Clock,\n Code2,\n Loader2,\n Play,\n RotateCcw,\n Terminal,\n XCircle,\n} from 'lucide-react';\nimport { Button, Textarea } from '@burdenoff/fe-libs/ui';\nimport { IoBlock } from '../SubmissionViews';\nimport { humanizeEnum } from '../../utils/format';\nimport { cn } from '../../utils/cn';\nimport { userMessageFromError } from '../../lib/errorMessage';\nimport { useRunLessonCode, type TecLesson, type TecLessonCodeRun } from '../../api/technospamApi';\n\n/**\n * A cold code sandbox can take up to a few minutes to start. While the API\n * answers WARMING we call it again on this interval, giving up after the\n * budget below so the learner can retry by hand.\n */\nconst WARMING_RETRY_MS = 4_000;\nconst WARMING_BUDGET_MS = 4 * 60_000;\n\nfunction runSummary(run: TecLessonCodeRun): {\n tone: 'success' | 'error' | 'neutral';\n text: string;\n} {\n if (run.compileFailed) return { tone: 'error', text: 'Compile error' };\n if (run.timedOut) return { tone: 'error', text: 'Time limit exceeded' };\n if (run.memoryLimitExceeded) return { tone: 'error', text: 'Memory limit exceeded' };\n if (run.exitCode !== 0) return { tone: 'error', text: `Exited with code ${run.exitCode}` };\n if (run.matchedExpected === true)\n return { tone: 'success', text: 'Output matches the expected output' };\n if (run.matchedExpected === false) return { tone: 'error', text: 'Output does not match yet' };\n return { tone: 'neutral', text: 'Ran successfully' };\n}\n\n/**\n * Runnable workspace for an INTERACTIVE lesson (BOFF-4107). Mount it with\n * `key={lesson.id}` so moving to another lesson starts a fresh editor: an editor\n * pre-filled with the lesson's starter code, an optional stdin box, and the\n * run output. Code runs only in the platform sandbox via `tecRunLessonCode`;\n * when the lesson has an expected output, a matching run completes the lesson\n * server-side and `onCompleted` lets the page refresh progress.\n */\nexport function InteractiveWorkspace({\n lesson,\n onCompleted,\n}: {\n lesson: TecLesson;\n onCompleted: () => void;\n}) {\n const starter = lesson.starterCode ?? '';\n const [code, setCode] = useState(starter);\n const [stdin, setStdin] = useState(lesson.sampleInput ?? '');\n const [run, setRun] = useState<TecLessonCodeRun | null>(null);\n const [warming, setWarming] = useState(false);\n const [running, setRunning] = useState(false);\n /** Why the last run was refused (for example a spent sandbox quota), shown inline. */\n const [runError, setRunError] = useState<string | null>(null);\n const warmingSince = useRef<number | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const [runLessonCode] = useRunLessonCode();\n\n // The page mounts one workspace per lesson (keyed by lesson id), so the\n // editor starts fresh on every lesson; only the pending retry needs cleanup.\n useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current);\n },\n []\n );\n\n const execute = async (): Promise<void> => {\n setRunning(true);\n setRunError(null);\n try {\n const res = await runLessonCode({\n variables: {\n input: {\n lessonId: lesson.id,\n language: lesson.language ?? undefined,\n code,\n stdin,\n },\n },\n });\n const result = res.data?.tecRunLessonCode;\n if (!result) {\n // The mutation failed (for example a spent sandbox quota). Stop any\n // warm-up polling, re-enable Run and say why next to the editor, where\n // the learner is looking, not only in a transient toast.\n setWarming(false);\n warmingSince.current = null;\n setRun(null);\n setRunError(\n userMessageFromError(res.error, 'Your code could not be run. Please try again.')\n );\n return;\n }\n if (result.status === 'WARMING') {\n warmingSince.current ??= Date.now();\n if (Date.now() - warmingSince.current < WARMING_BUDGET_MS) {\n setWarming(true);\n timer.current = setTimeout(() => void execute(), WARMING_RETRY_MS);\n return;\n }\n setWarming(false);\n warmingSince.current = null;\n setRun({ ...result, status: 'UNAVAILABLE' });\n return;\n }\n setWarming(false);\n warmingSince.current = null;\n setRun(result);\n if (result.lessonCompleted) onCompleted();\n } finally {\n setRunning(false);\n }\n };\n\n const busy = running || warming;\n const summary = run && run.status === 'COMPLETED' ? runSummary(run) : null;\n\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-hidden rounded-xl border border-border-strong bg-bg-sunken shadow-sm\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border-seam bg-bg-canvas/40 px-4 py-2\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-error-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-warning-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-success-border\" />\n </div>\n <span className=\"inline-flex items-center gap-1.5 font-mono text-xs text-text-secondary\">\n <Code2 size={13} /> {lesson.language ? humanizeEnum(lesson.language) : 'code'}\n </span>\n </div>\n <Textarea\n aria-label=\"Lesson code editor\"\n value={code}\n onChange={(e) => setCode(e.target.value)}\n placeholder=\"Write your code…\"\n className=\"min-h-[260px] resize-y rounded-none border-0 bg-transparent font-mono text-xs leading-relaxed focus-visible:ring-0 focus-visible:ring-offset-0\"\n spellCheck={false}\n />\n </div>\n\n <div>\n <label\n htmlFor={`tec-lesson-stdin-${lesson.id}`}\n className=\"mb-1 block text-xs font-medium uppercase tracking-wide text-text-muted\"\n >\n Input (stdin)\n </label>\n <Textarea\n id={`tec-lesson-stdin-${lesson.id}`}\n value={stdin}\n onChange={(e) => setStdin(e.target.value)}\n placeholder=\"Optional input your program reads\"\n className=\"min-h-[64px] font-mono text-xs\"\n spellCheck={false}\n />\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button onClick={() => void execute()} disabled={busy || !code.trim()}>\n {busy ? <Loader2 size={16} className=\"animate-spin\" /> : <Play size={16} />}\n {warming ? 'Starting sandbox…' : running ? 'Running…' : 'Run code'}\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => {\n setCode(starter);\n setRun(null);\n setRunError(null);\n }}\n disabled={busy || code === starter}\n >\n <RotateCcw size={15} /> Reset to starter\n </Button>\n <span className=\"text-xs text-text-muted\">Runs in an isolated sandbox.</span>\n </div>\n\n {warming ? (\n <p\n role=\"status\"\n className=\"rounded-lg border border-border-seam bg-bg-sunken px-3 py-2 text-sm text-text-secondary\"\n >\n The code sandbox is starting up. Your code will run automatically as soon as it is ready.\n </p>\n ) : null}\n\n {runError ? (\n <p\n role=\"alert\"\n data-testid=\"lesson-run-error\"\n className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\"\n >\n {runError}\n </p>\n ) : null}\n\n {run?.status === 'UNAVAILABLE' ? (\n <p\n role=\"alert\"\n className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\"\n >\n The code sandbox is not available right now. Please try again in a moment.\n </p>\n ) : null}\n\n {run && summary ? (\n <div\n className=\"space-y-3 rounded-xl border border-border-seam p-4\"\n data-testid=\"lesson-run-output\"\n >\n <div className=\"flex flex-wrap items-center gap-3\">\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 text-sm font-medium',\n summary.tone === 'success' && 'text-status-success-text',\n summary.tone === 'error' && 'text-status-error-text',\n summary.tone === 'neutral' && 'text-text-primary'\n )}\n >\n {summary.tone === 'error' ? <XCircle size={16} /> : <CheckCircle2 size={16} />}\n {summary.text}\n </span>\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Clock size={12} /> {run.durationMs} ms\n </span>\n {run.lessonCompleted ? (\n <span className=\"rounded-full border border-status-success-border bg-status-success-bg-subtle px-2 py-0.5 text-xs font-medium text-status-success-text\">\n Lesson completed\n </span>\n ) : null}\n </div>\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <IoBlock label=\"Output\" value={run.stdout} />\n {lesson.expectedOutput ? (\n <IoBlock label=\"Expected output\" value={lesson.expectedOutput} />\n ) : null}\n </div>\n {run.stderr ? (\n <div>\n <p className=\"mb-1 flex items-center gap-1 text-xs font-medium uppercase tracking-wide text-text-muted\">\n <Terminal size={12} /> Errors\n </p>\n <pre className=\"overflow-auto rounded-lg bg-status-error-bg-subtle px-3 py-2 font-mono text-xs text-status-error-text\">\n {run.stderr}\n </pre>\n </div>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminAdminDashboardPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/AdminAdminDashboardPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AdminAdminDashboardPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/AdminAdminDashboardPagePage.tsx"],"names":[],"mappings":"AA4nDA,wBAAgB,2BAA2B,gCA0D1C"}
|