From 0edf78b7fd0ed2d9701adb0cf3885d0872112bed Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Wed, 18 Jun 2025 11:06:44 +0530 Subject: [PATCH 1/6] feat: programming exercises --- frontend/components.d.ts | 1 + .../Modals/ProgrammingExerciseModal.vue | 53 +++++++++++++ frontend/src/pages/ProgrammingExercise.vue | 44 +++++++++++ frontend/src/utils/program.ts | 75 +++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 frontend/src/components/Modals/ProgrammingExerciseModal.vue create mode 100644 frontend/src/pages/ProgrammingExercise.vue create mode 100644 frontend/src/utils/program.ts diff --git a/frontend/components.d.ts b/frontend/components.d.ts index 09f63fdd..8df8bed5 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -77,6 +77,7 @@ declare module 'vue' { PageModal: typeof import('./src/components/Modals/PageModal.vue')['default'] PaymentSettings: typeof import('./src/components/Settings/PaymentSettings.vue')['default'] Play: typeof import('./src/components/Icons/Play.vue')['default'] + ProgrammingExerciseModal: typeof import('./src/components/Modals/ProgrammingExerciseModal.vue')['default'] ProgressBar: typeof import('./src/components/ProgressBar.vue')['default'] Question: typeof import('./src/components/Modals/Question.vue')['default'] Quiz: typeof import('./src/components/Quiz.vue')['default'] diff --git a/frontend/src/components/Modals/ProgrammingExerciseModal.vue b/frontend/src/components/Modals/ProgrammingExerciseModal.vue new file mode 100644 index 00000000..fd30be91 --- /dev/null +++ b/frontend/src/components/Modals/ProgrammingExerciseModal.vue @@ -0,0 +1,53 @@ + + diff --git a/frontend/src/pages/ProgrammingExercise.vue b/frontend/src/pages/ProgrammingExercise.vue new file mode 100644 index 00000000..d34b999f --- /dev/null +++ b/frontend/src/pages/ProgrammingExercise.vue @@ -0,0 +1,44 @@ + + diff --git a/frontend/src/utils/program.ts b/frontend/src/utils/program.ts new file mode 100644 index 00000000..5e36a2ec --- /dev/null +++ b/frontend/src/utils/program.ts @@ -0,0 +1,75 @@ +import { createApp, h } from 'vue' +import { Code } from 'lucide-vue-next' +import translationPlugin from '@/translation' +import ProgrammingExerciseModal from '@/components/Modals/ProgrammingExerciseModal.vue'; + +export class Program { + + data: any; + api: any; + readOnly: boolean; + wrapper: HTMLDivElement; + + constructor({ data, api, readOnly }: { data: any; api: any; readOnly: boolean }) { + this.data = data; + this.api = api; + this.readOnly = readOnly; + } + + static get toolbox() { + const app = createApp({ + render: () => h(Code, { size: 5, strokeWidth: 1.5 }), + }) + + const div = document.createElement('div') + app.mount(div) + + return { + title: __('Programming Exercise'), + icon: div.innerHTML, + } + } + + static get isReadOnlySupported() { + return true + } + + render() { + this.wrapper = document.createElement('div') + if (Object.keys(this.data).length) { + this.renderExercise(this.data.exercise) + } else { + this.renderModal() + } + return this.wrapper + } + + renderModal() { + if (this.readOnly) { + return + } + const app = createApp(ProgrammingExerciseModal, { + onSave: (exercise: string) => { + this.data.exercise = exercise + this.renderExercise(exercise) + }, + }) + app.use(translationPlugin) + app.mount(this.wrapper) + } + + renderExercise(exercise: string) { + this.wrapper.innerHTML = `
+ + Programming Exercise: ${exercise} + +
` + return + } + + save() { + return { + exercise: this.data.exercise, + } + } +} \ No newline at end of file From 9bb4c45a237b4900fcb1ccd418cef18b7c19fae2 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Thu, 19 Jun 2025 14:47:52 +0530 Subject: [PATCH 2/6] feat: programming exercise submission --- frontend/components.d.ts | 1 + frontend/package.json | 8 +- frontend/src/components/Controls/Code.vue | 156 +++++++++ frontend/src/index.css | 1 + frontend/src/pages/ProgrammingExercise.vue | 44 --- .../ProgrammingExerciseForm.vue | 0 .../ProgrammingExerciseSubmission.vue | 307 ++++++++++++++++++ .../ProgrammingExerciseSubmissions.vue | 0 .../ProgrammingExercises.vue | 0 frontend/src/router.js | 31 ++ frontend/src/styles/codemirror.css | 65 ++++ lms/lms/api.py | 72 ++++ .../lms_programming_exercise/__init__.py | 0 .../lms_programming_exercise.js | 8 + .../lms_programming_exercise.json | 91 ++++++ .../lms_programming_exercise.py | 9 + .../test_lms_programming_exercise.py | 30 ++ .../__init__.py | 0 .../lms_programming_exercise_submission.js | 8 + .../lms_programming_exercise_submission.json | 110 +++++++ .../lms_programming_exercise_submission.py | 9 + ...est_lms_programming_exercise_submission.py | 30 ++ lms/lms/doctype/lms_test_case/__init__.py | 0 .../doctype/lms_test_case/lms_test_case.js | 8 + .../doctype/lms_test_case/lms_test_case.json | 45 +++ .../doctype/lms_test_case/lms_test_case.py | 9 + .../lms_test_case/test_lms_test_case.py | 30 ++ .../lms_test_case_submission/__init__.py | 0 .../lms_test_case_submission.json | 62 ++++ .../lms_test_case_submission.py | 9 + yarn.lock | 163 ++++++++-- 31 files changed, 1237 insertions(+), 69 deletions(-) create mode 100644 frontend/src/components/Controls/Code.vue delete mode 100644 frontend/src/pages/ProgrammingExercise.vue create mode 100644 frontend/src/pages/ProgrammingExercises/ProgrammingExerciseForm.vue create mode 100644 frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue create mode 100644 frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmissions.vue create mode 100644 frontend/src/pages/ProgrammingExercises/ProgrammingExercises.vue create mode 100644 frontend/src/styles/codemirror.css create mode 100644 lms/lms/doctype/lms_programming_exercise/__init__.py create mode 100644 lms/lms/doctype/lms_programming_exercise/lms_programming_exercise.js create mode 100644 lms/lms/doctype/lms_programming_exercise/lms_programming_exercise.json create mode 100644 lms/lms/doctype/lms_programming_exercise/lms_programming_exercise.py create mode 100644 lms/lms/doctype/lms_programming_exercise/test_lms_programming_exercise.py create mode 100644 lms/lms/doctype/lms_programming_exercise_submission/__init__.py create mode 100644 lms/lms/doctype/lms_programming_exercise_submission/lms_programming_exercise_submission.js create mode 100644 lms/lms/doctype/lms_programming_exercise_submission/lms_programming_exercise_submission.json create mode 100644 lms/lms/doctype/lms_programming_exercise_submission/lms_programming_exercise_submission.py create mode 100644 lms/lms/doctype/lms_programming_exercise_submission/test_lms_programming_exercise_submission.py create mode 100644 lms/lms/doctype/lms_test_case/__init__.py create mode 100644 lms/lms/doctype/lms_test_case/lms_test_case.js create mode 100644 lms/lms/doctype/lms_test_case/lms_test_case.json create mode 100644 lms/lms/doctype/lms_test_case/lms_test_case.py create mode 100644 lms/lms/doctype/lms_test_case/test_lms_test_case.py create mode 100644 lms/lms/doctype/lms_test_case_submission/__init__.py create mode 100644 lms/lms/doctype/lms_test_case_submission/lms_test_case_submission.json create mode 100644 lms/lms/doctype/lms_test_case_submission/lms_test_case_submission.py diff --git a/frontend/components.d.ts b/frontend/components.d.ts index 8df8bed5..2e6c67de 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -32,6 +32,7 @@ declare module 'vue' { Categories: typeof import('./src/components/Settings/Categories.vue')['default'] CertificationLinks: typeof import('./src/components/CertificationLinks.vue')['default'] ChapterModal: typeof import('./src/components/Modals/ChapterModal.vue')['default'] + Code: typeof import('./src/components/Controls/Code.vue')['default'] CodeEditor: typeof import('./src/components/Controls/CodeEditor.vue')['default'] CollapseSidebar: typeof import('./src/components/Icons/CollapseSidebar.vue')['default'] CourseCard: typeof import('./src/components/CourseCard.vue')['default'] diff --git a/frontend/package.json b/frontend/package.json index bb7a91da..a7df7298 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,6 +10,10 @@ "copy-html-entry": "cp ../lms/public/frontend/index.html ../lms/www/lms.html" }, "dependencies": { + "@codemirror/lang-html": "^6.4.9", + "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-json": "^6.0.1", + "@codemirror/lang-python": "^6.2.1", "@editorjs/checklist": "^1.6.0", "@editorjs/code": "^2.9.0", "@editorjs/editorjs": "^2.29.0", @@ -24,7 +28,7 @@ "ace-builds": "^1.36.2", "apexcharts": "^4.3.0", "chart.js": "^4.4.1", - "codemirror-editor-vue3": "^2.8.0", + "codemirror": "^6.0.1", "dayjs": "^1.11.6", "feather-icons": "^4.28.0", "frappe-ui": "^0.1.147", @@ -35,9 +39,11 @@ "plyr": "^3.7.8", "socket.io-client": "^4.7.2", "tailwindcss": "3.4.15", + "thememirror": "^2.0.1", "typescript": "^5.7.2", "vue": "^3.4.23", "vue-chartjs": "^5.3.0", + "vue-codemirror": "^6.1.1", "vue-draggable-next": "^2.2.1", "vue-router": "^4.0.12", "vue3-apexcharts": "^1.8.0", diff --git a/frontend/src/components/Controls/Code.vue b/frontend/src/components/Controls/Code.vue new file mode 100644 index 00000000..a14060b8 --- /dev/null +++ b/frontend/src/components/Controls/Code.vue @@ -0,0 +1,156 @@ + + + diff --git a/frontend/src/index.css b/frontend/src/index.css index 166ac595..92b6d76d 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,2 +1,3 @@ @import './assets/Inter/inter.css'; @import 'frappe-ui/src/style.css'; +@import './styles/codemirror.css'; \ No newline at end of file diff --git a/frontend/src/pages/ProgrammingExercise.vue b/frontend/src/pages/ProgrammingExercise.vue deleted file mode 100644 index d34b999f..00000000 --- a/frontend/src/pages/ProgrammingExercise.vue +++ /dev/null @@ -1,44 +0,0 @@ - - diff --git a/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseForm.vue b/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseForm.vue new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue b/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue new file mode 100644 index 00000000..d3512ea0 --- /dev/null +++ b/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue @@ -0,0 +1,307 @@ +