+ The course becomes a studio course with the same id, so learners keep their progress and notes. The manifest,
+ lessons and small files go into a git repository you edit on a draft and publish. Videos and other large files
+ stay outside git, on this server, and keep playing at the same paths. Visibility does not change.
+
+ {running ? (
+
+
+ {phase.message ?? "Waiting to start…"}
+
+ ) : null}
+ {phase.kind === "failed" ?
{phase.error}
: null}
+
+ {phase.kind === "failed" ? "Try again" : "Make editable in the studio"}
+
+
+ );
+}
+
+/** Starts the conversion job and polls it; calls `onDone` once the course is a studio course. */
+export function ConvertPanel({ courseId, onDone }: { courseId: string; onDone: () => void }) {
+ const [phase, setPhase] = useState({ kind: "idle" });
+ const live = useRef(true);
+ useEffect(() => () => { live.current = false; }, []);
+
+ const start = async () => {
+ setPhase({ kind: "running", progress: 0, message: null });
+ const { status, data } = await api("POST", coursePath(courseId, "/convert"));
+ if (status !== 202) return setPhase({ kind: "failed", error: data?.error ?? `Could not start (${status})` });
+ for (;;) {
+ await new Promise((r) => setTimeout(r, 700));
+ if (!live.current) return;
+ const j = await api("GET", `/api/studio/jobs/${encodeURIComponent(data.jobId)}`);
+ if (j.status !== 200) return setPhase({ kind: "failed", error: j.data?.error ?? `Could not follow the conversion (${j.status})` });
+ if (j.data.status === "done") return onDone();
+ if (j.data.status === "failed") return setPhase({ kind: "failed", error: j.data.error ?? "The conversion failed" });
+ setPhase({ kind: "running", progress: j.data.progress ?? 0, message: j.data.message });
+ }
+ };
+ return ;
+}
+
+/** What the studio shows for a course it does not manage. */
+export function ReadOnlyView({ courseId, info, onConverted }: { courseId: string; info: ReadOnlyInfo; onConverted: () => void }) {
+ if (info.imported) {
+ return (
+ <>
+
+ Imported course.{" "}
+ {info.convertible ? "It is read-only until you make it editable in the studio." : "It is read-only here. Only the owner can make it editable in the studio."}
+
These courses come from repositories the platform does not own. Edit them in their own repository.
+
These courses come from repositories the platform does not own, or from imports. Edit them in their own repository; the owner can make an imported course editable here.