This commit is contained in:
2025-11-11 14:19:03 -07:00
parent 7fec0424d7
commit 890e08d1b2
6 changed files with 46 additions and 16 deletions

View File

@@ -22,6 +22,7 @@ import {
} from "@/features/local/course/localCourseSettings";
import { useCourseListInTermQuery } from "@/features/canvas/hooks/canvasCourseHooks";
import { useCanvasTermsQuery } from "@/features/canvas/hooks/canvasHooks";
import { useDirectoryExistsQuery } from "@/features/local/utils/storageDirectoryHooks";
const sampleCompose = `services:
canvas_manager:
@@ -62,7 +63,6 @@ export default function AddNewCourseToGlobalSettingsForm() {
const formIsComplete =
selectedTerm && selectedCanvasCourse && selectedDirectory;
return (
<div>
<ButtonSelect
@@ -95,7 +95,12 @@ export default function AddNewCourseToGlobalSettingsForm() {
disabled={!formIsComplete || createCourse.isPending}
onClick={async () => {
if (formIsComplete) {
console.log("Creating course with settings:", selectedDirectory, "old course", courseToImport);
console.log(
"Creating course with settings:",
selectedDirectory,
"old course",
courseToImport
);
const newSettings: LocalCourseSettings = courseToImport
? {
...courseToImport,
@@ -145,11 +150,6 @@ export default function AddNewCourseToGlobalSettingsForm() {
</button>
</div>
{createCourse.isPending && <Spinner />}
{/* <pre>
<div>Example docker compose</div>
<code className="language-yml">{sampleCompose}</code>
</pre> */}
</div>
);
}
@@ -185,6 +185,8 @@ function OtherSettings({
useCourseListInTermQuery(selectedTerm.id);
const { data: allSettings } = useLocalCoursesSettingsQuery();
const [directory, setDirectory] = useState("./");
const { data: directoryExists, isLoading: directoryExistsLoading } =
useDirectoryExistsQuery(directory);
const populatedCanvasCourseIds = allSettings?.map((s) => s.canvasId) ?? [];
const availableCourses =
@@ -224,6 +226,15 @@ function OtherSettings({
setLastTypedValue={setSelectedDirectory}
label={"Storage Folder"}
/>
<div className="text-center mt-2 min-h-6">
{directoryExistsLoading && <Spinner />}
{!directoryExistsLoading && directoryExists && (
<div className="text-red-300">Directory must be a new folder</div>
)}
{!directoryExistsLoading && directoryExists === false && (
<div className="text-green-300"> New folder</div>
)}
</div>
<br />
<div className="flex justify-center">
<DayOfWeekInput

View File

@@ -47,7 +47,7 @@ export const CalendarMonth = ({ month }: { month: CalendarMonthModel }) => {
className={
"text-2xl transition-all duration-500 " +
"hover:text-slate-50 underline hover:scale-105 " +
"flex "
"flex cursor-pointer"
}
onClick={() => setIsExpanded((e) => !e)}
role="button"

View File

@@ -25,4 +25,13 @@ export const directoriesRouter = router({
.query(async ({ input: { folderPath } }) => {
return await fileStorageService.settings.folderIsCourse(folderPath);
}),
directoryExists: publicProcedure
.input(
z.object({
relativePath: z.string(),
})
)
.query(async ({ input: { relativePath } }) => {
return await fileStorageService.directoryExists(relativePath);
}),
});

View File

@@ -72,4 +72,15 @@ export const fileStorageService = {
}
return { files, folders };
},
async directoryExists(relativePath: string): Promise<boolean> {
const fullPath = path.join(basePath, relativePath);
// Security: ensure fullPath is inside basePath
const resolvedBase = path.resolve(basePath);
const resolvedFull = path.resolve(fullPath);
if (!resolvedFull.startsWith(resolvedBase)) {
return false;
}
return await directoryOrFileExists(fullPath);
},
};

View File

@@ -23,3 +23,10 @@ export const useDirectoryIsCourseQuery = (folderPath: string) => {
trpc.directories.directoryIsCourse.queryOptions({ folderPath })
);
};
export const useDirectoryExistsQuery = (relativePath: string) => {
const trpc = useTRPC();
return useQuery(
trpc.directories.directoryExists.queryOptions({ relativePath })
);
};