@testgorilla/tgo-coding-test 0.0.1 → 1.0.0
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/README.md +49 -2
- package/esm2022/index.mjs +12 -0
- package/esm2022/lib/components/code-editor/code-editor.component.mjs +335 -0
- package/esm2022/lib/components/code-editor/code-editor.service.mjs +72 -0
- package/esm2022/lib/components/code-editor/helpers/c-helper.mjs +40 -0
- package/esm2022/lib/components/code-editor/helpers/code-editor-helper.base.mjs +11 -0
- package/esm2022/lib/components/code-editor/helpers/code-editor-helper.model.mjs +2 -0
- package/esm2022/lib/components/code-editor/helpers/cpp-helper.mjs +41 -0
- package/esm2022/lib/components/code-editor/helpers/csharp-helper.mjs +42 -0
- package/esm2022/lib/components/code-editor/helpers/go-helper.mjs +42 -0
- package/esm2022/lib/components/code-editor/helpers/index.mjs +16 -0
- package/esm2022/lib/components/code-editor/helpers/java-helper.mjs +42 -0
- package/esm2022/lib/components/code-editor/helpers/javascript-helper.mjs +26 -0
- package/esm2022/lib/components/code-editor/helpers/kotlin-helper.mjs +42 -0
- package/esm2022/lib/components/code-editor/helpers/php-helper.mjs +26 -0
- package/esm2022/lib/components/code-editor/helpers/python-helper.mjs +26 -0
- package/esm2022/lib/components/code-editor/helpers/r-helper.mjs +26 -0
- package/esm2022/lib/components/code-editor/helpers/ruby-helper.mjs +26 -0
- package/esm2022/lib/components/code-editor/helpers/scala-helper.mjs +41 -0
- package/esm2022/lib/components/code-editor/helpers/sql-helper.mjs +34 -0
- package/esm2022/lib/components/code-editor/helpers/swift-helper.mjs +40 -0
- package/esm2022/lib/components/code-editor/helpers/typescript-helper.mjs +41 -0
- package/esm2022/lib/components/code-editor/models/code-editor.model.mjs +2 -0
- package/esm2022/lib/components/code-editor/models/coding-snapshot.model.mjs +2 -0
- package/esm2022/lib/components/coding-question/coding-question.component.mjs +126 -0
- package/esm2022/lib/components/coding-section/coding-section.component.mjs +188 -0
- package/esm2022/lib/components/common/truncated-text/truncated-text.component.mjs +38 -0
- package/esm2022/lib/components/configurations/configurations.component.mjs +97 -0
- package/esm2022/lib/components/instructions/instructions.component.mjs +139 -0
- package/esm2022/lib/components/panel/panel.component.mjs +34 -0
- package/esm2022/lib/components/runnable-editor/runnable-editor.component.mjs +169 -0
- package/esm2022/lib/components/tests/test-cases/test-cases.component.mjs +198 -0
- package/esm2022/lib/components/tests/test-cases-content/test-cases-content.component.mjs +96 -0
- package/esm2022/lib/components/tests/test-cases-status/test-cases-status.component.mjs +21 -0
- package/esm2022/lib/components/tests/test-results.component.mjs +127 -0
- package/esm2022/lib/components/tgo-coding-test/tgo-coding-test.component.mjs +280 -0
- package/esm2022/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.mjs +476 -0
- package/esm2022/lib/config/index.mjs +2 -0
- package/esm2022/lib/config/tgo-coding-test.config.mjs +2 -0
- package/esm2022/lib/config/tgo-coding-test.provider.mjs +34 -0
- package/esm2022/lib/config/tgo-coding-test.token.mjs +14 -0
- package/esm2022/lib/models/auto-saved-data.mjs +2 -0
- package/esm2022/lib/models/code-event.mjs +2 -0
- package/esm2022/lib/models/coderunner-execution-results.mjs +2 -0
- package/esm2022/lib/models/configs.mjs +2 -0
- package/esm2022/lib/models/language-change-action.mjs +2 -0
- package/esm2022/lib/models/lat-languages.mjs +3 -0
- package/esm2022/lib/models/mixpanel-events.mjs +2 -0
- package/esm2022/lib/models/mode.mjs +2 -0
- package/esm2022/lib/models/paste-data.mjs +2 -0
- package/esm2022/lib/models/programming-language.mjs +2 -0
- package/esm2022/lib/models/test-cases.mjs +7 -0
- package/esm2022/lib/models/theme.mjs +2 -0
- package/esm2022/lib/models/translations.mjs +2 -0
- package/esm2022/lib/models/view-mode.mjs +8 -0
- package/esm2022/lib/pipes/memoize-func.pipe.mjs +39 -0
- package/esm2022/lib/services/candidate-coding-test-services/candidature-api.service.mjs +19 -0
- package/esm2022/lib/services/candidate-coding-test-services/coderunner-api.service.mjs +58 -0
- package/esm2022/lib/services/candidate-coding-test-services/coding-test-tour.service.mjs +89 -0
- package/esm2022/lib/services/candidate-coding-test-services/coding-test.service.mjs +490 -0
- package/esm2022/lib/services/candidate-coding-test-services/index.mjs +5 -0
- package/esm2022/lib/services/coding-test-config.service.mjs +51 -0
- package/esm2022/lib/services/configurations.service.mjs +89 -0
- package/esm2022/lib/services/lib-coding-test.service.mjs +106 -0
- package/esm2022/lib/services/storage.service.mjs +624 -0
- package/esm2022/lib/services/test-cases.service.mjs +30 -0
- package/esm2022/lib/services/theme.service.mjs +36 -0
- package/esm2022/lib/utils/additional-languages/erlang.mjs +103 -0
- package/esm2022/lib/utils/resize-element.mjs +13 -0
- package/esm2022/lib/utils/time-to-ms.util.mjs +11 -0
- package/esm2022/shared/index.mjs +5 -0
- package/esm2022/shared/lib/components/audio-animation/audio-animation.component.mjs +114 -0
- package/esm2022/shared/lib/components/audio-animation/index.mjs +2 -0
- package/esm2022/shared/lib/components/index.mjs +3 -0
- package/esm2022/shared/lib/components/vimeo-video/index.mjs +2 -0
- package/esm2022/shared/lib/components/vimeo-video/vimeo-video.component.mjs +101 -0
- package/esm2022/shared/lib/models/answer.mjs +2 -0
- package/esm2022/shared/lib/models/assessment.mjs +2 -0
- package/esm2022/shared/lib/models/environment.mjs +2 -0
- package/esm2022/shared/lib/models/index.mjs +9 -0
- package/esm2022/shared/lib/models/question-component.mjs +2 -0
- package/esm2022/shared/lib/models/question.mjs +2 -0
- package/esm2022/shared/lib/models/test.mjs +2 -0
- package/esm2022/shared/lib/models/translations.mjs +2 -0
- package/esm2022/shared/lib/models/window.mjs +2 -0
- package/esm2022/shared/lib/services/api/api.service.mjs +97 -0
- package/esm2022/shared/lib/services/api/mocked-api.service.mjs +131 -0
- package/esm2022/shared/lib/services/environment/environment.service.mjs +13 -0
- package/esm2022/shared/lib/services/index.mjs +10 -0
- package/esm2022/shared/lib/services/localization/languages.model.mjs +19 -0
- package/esm2022/shared/lib/services/localization/transloco-lazy-module-utils.mjs +27 -0
- package/esm2022/shared/lib/services/localization/transloco-testing.module.mjs +11 -0
- package/esm2022/shared/lib/services/media/media.service.mjs +129 -0
- package/esm2022/shared/lib/services/mixpanel/mixpanel.service.mjs +30 -0
- package/esm2022/shared/lib/services/theme/theme.service.mjs +24 -0
- package/esm2022/shared/test-mocks/assessment-test.mock.mjs +112 -0
- package/esm2022/shared/test-mocks/index.mjs +3 -0
- package/esm2022/shared/test-mocks/tgo-ui.mock.mjs +39 -0
- package/esm2022/testgorilla-tgo-coding-test.mjs +5 -0
- package/fesm2022/testgorilla-tgo-coding-test.mjs +4526 -0
- package/fesm2022/testgorilla-tgo-coding-test.mjs.map +1 -0
- package/{src/index.ts → index.d.ts} +2 -19
- package/lib/components/code-editor/code-editor.component.d.ts +54 -0
- package/lib/components/code-editor/code-editor.service.d.ts +12 -0
- package/lib/components/code-editor/helpers/c-helper.d.ts +11 -0
- package/lib/components/code-editor/helpers/code-editor-helper.base.d.ts +8 -0
- package/lib/components/code-editor/helpers/code-editor-helper.model.d.ts +62 -0
- package/lib/components/code-editor/helpers/cpp-helper.d.ts +11 -0
- package/lib/components/code-editor/helpers/csharp-helper.d.ts +12 -0
- package/lib/components/code-editor/helpers/go-helper.d.ts +12 -0
- package/lib/components/code-editor/helpers/java-helper.d.ts +12 -0
- package/lib/components/code-editor/helpers/javascript-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/kotlin-helper.d.ts +12 -0
- package/lib/components/code-editor/helpers/php-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/python-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/r-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/ruby-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/scala-helper.d.ts +12 -0
- package/lib/components/code-editor/helpers/sql-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/swift-helper.d.ts +11 -0
- package/lib/components/code-editor/helpers/typescript-helper.d.ts +11 -0
- package/lib/components/code-editor/models/code-editor.model.d.ts +8 -0
- package/lib/components/code-editor/models/coding-snapshot.model.d.ts +4 -0
- package/lib/components/coding-question/coding-question.component.d.ts +45 -0
- package/lib/components/coding-section/coding-section.component.d.ts +52 -0
- package/lib/components/common/truncated-text/truncated-text.component.d.ts +13 -0
- package/lib/components/configurations/configurations.component.d.ts +40 -0
- package/lib/components/instructions/instructions.component.d.ts +48 -0
- package/lib/components/panel/panel.component.d.ts +12 -0
- package/lib/components/runnable-editor/runnable-editor.component.d.ts +53 -0
- package/lib/components/tests/test-cases/test-cases.component.d.ts +46 -0
- package/lib/components/tests/test-cases-content/test-cases-content.component.d.ts +26 -0
- package/lib/components/tests/test-cases-status/test-cases-status.component.d.ts +9 -0
- package/lib/components/tests/test-results.component.d.ts +33 -0
- package/lib/components/tgo-coding-test/tgo-coding-test.component.d.ts +69 -0
- package/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.d.ts +101 -0
- package/{src/lib/config/index.ts → lib/config/index.d.ts} +0 -1
- package/lib/config/tgo-coding-test.config.d.ts +24 -0
- package/{src/lib/config/tgo-coding-test.provider.ts → lib/config/tgo-coding-test.provider.d.ts} +6 -18
- package/lib/config/tgo-coding-test.token.d.ts +9 -0
- package/lib/models/auto-saved-data.d.ts +42 -0
- package/lib/models/code-event.d.ts +15 -0
- package/lib/models/coderunner-execution-results.d.ts +51 -0
- package/lib/models/configs.d.ts +15 -0
- package/lib/models/language-change-action.d.ts +4 -0
- package/lib/models/lat-languages.d.ts +8 -0
- package/lib/models/mixpanel-events.d.ts +3 -0
- package/lib/models/mode.d.ts +5 -0
- package/lib/models/paste-data.d.ts +4 -0
- package/lib/models/programming-language.d.ts +8 -0
- package/lib/models/test-cases.d.ts +67 -0
- package/lib/models/theme.d.ts +4 -0
- package/lib/models/translations.d.ts +1 -0
- package/lib/models/view-mode.d.ts +6 -0
- package/{src/lib/pipes/memoize-func.pipe.ts → lib/pipes/memoize-func.pipe.d.ts} +6 -14
- package/lib/services/candidate-coding-test-services/candidature-api.service.d.ts +10 -0
- package/lib/services/candidate-coding-test-services/coderunner-api.service.d.ts +18 -0
- package/lib/services/candidate-coding-test-services/coding-test-tour.service.d.ts +22 -0
- package/lib/services/candidate-coding-test-services/coding-test.service.d.ts +68 -0
- package/{src/lib/services/candidate-coding-test-services/index.ts → lib/services/candidate-coding-test-services/index.d.ts} +1 -1
- package/lib/services/coding-test-config.service.d.ts +38 -0
- package/lib/services/configurations.service.d.ts +37 -0
- package/lib/services/lib-coding-test.service.d.ts +69 -0
- package/lib/services/storage.service.d.ts +83 -0
- package/lib/services/test-cases.service.d.ts +12 -0
- package/lib/services/theme.service.d.ts +17 -0
- package/lib/utils/additional-languages/erlang.d.ts +37 -0
- package/lib/utils/resize-element.d.ts +2 -0
- package/lib/utils/time-to-ms.util.d.ts +1 -0
- package/package.json +18 -7
- package/shared/index.d.ts +4 -0
- package/shared/lib/components/audio-animation/audio-animation.component.d.ts +27 -0
- package/shared/lib/components/audio-animation/index.d.ts +1 -0
- package/shared/lib/components/index.d.ts +2 -0
- package/shared/lib/components/vimeo-video/index.d.ts +1 -0
- package/shared/lib/components/vimeo-video/vimeo-video.component.d.ts +24 -0
- package/shared/lib/models/answer.d.ts +17 -0
- package/shared/lib/models/assessment.d.ts +80 -0
- package/shared/lib/models/environment.d.ts +1 -0
- package/shared/lib/models/index.d.ts +8 -0
- package/shared/lib/models/question-component.d.ts +54 -0
- package/shared/lib/models/question.d.ts +102 -0
- package/shared/lib/models/test.d.ts +81 -0
- package/shared/lib/models/translations.d.ts +1 -0
- package/shared/lib/models/window.d.ts +6 -0
- package/shared/lib/services/api/api.service.d.ts +25 -0
- package/shared/lib/services/api/mocked-api.service.d.ts +35 -0
- package/shared/lib/services/environment/environment.service.d.ts +6 -0
- package/shared/lib/services/index.d.ts +9 -0
- package/shared/lib/services/localization/languages.model.d.ts +15 -0
- package/shared/lib/services/localization/transloco-lazy-module-utils.d.ts +11 -0
- package/shared/lib/services/localization/transloco-testing.module.d.ts +2 -0
- package/shared/lib/services/media/media.service.d.ts +29 -0
- package/shared/lib/services/mixpanel/mixpanel.service.d.ts +10 -0
- package/shared/lib/services/theme/theme.service.d.ts +8 -0
- package/shared/test-mocks/assessment-test.mock.d.ts +21 -0
- package/shared/test-mocks/index.d.ts +2 -0
- package/shared/test-mocks/tgo-ui.mock.d.ts +21 -0
- package/.eslintrc.json +0 -45
- package/jest.config.ts +0 -21
- package/ng-package.json +0 -14
- package/project.json +0 -36
- package/src/lib/components/.gitkeep +0 -0
- package/src/lib/components/code-editor/code-editor.component.html +0 -10
- package/src/lib/components/code-editor/code-editor.component.scss +0 -21
- package/src/lib/components/code-editor/code-editor.component.spec.ts +0 -136
- package/src/lib/components/code-editor/code-editor.component.ts +0 -369
- package/src/lib/components/code-editor/code-editor.mocks.ts +0 -28
- package/src/lib/components/code-editor/code-editor.service.spec.ts +0 -160
- package/src/lib/components/code-editor/code-editor.service.ts +0 -94
- package/src/lib/components/code-editor/helpers/c-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/c-helper.ts +0 -51
- package/src/lib/components/code-editor/helpers/code-editor-helper.base.spec.ts +0 -30
- package/src/lib/components/code-editor/helpers/code-editor-helper.base.ts +0 -16
- package/src/lib/components/code-editor/helpers/code-editor-helper.mocks.ts +0 -24
- package/src/lib/components/code-editor/helpers/code-editor-helper.model.ts +0 -67
- package/src/lib/components/code-editor/helpers/cpp-helper.spec.ts +0 -40
- package/src/lib/components/code-editor/helpers/cpp-helper.ts +0 -52
- package/src/lib/components/code-editor/helpers/csharp-helper.spec.ts +0 -42
- package/src/lib/components/code-editor/helpers/csharp-helper.ts +0 -55
- package/src/lib/components/code-editor/helpers/go-helper.spec.ts +0 -41
- package/src/lib/components/code-editor/helpers/go-helper.ts +0 -54
- package/src/lib/components/code-editor/helpers/java-helper.spec.ts +0 -41
- package/src/lib/components/code-editor/helpers/java-helper.ts +0 -54
- package/src/lib/components/code-editor/helpers/javascript-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/javascript-helper.ts +0 -32
- package/src/lib/components/code-editor/helpers/kotlin-helper.spec.ts +0 -41
- package/src/lib/components/code-editor/helpers/kotlin-helper.ts +0 -54
- package/src/lib/components/code-editor/helpers/php-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/php-helper.ts +0 -32
- package/src/lib/components/code-editor/helpers/python-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/python-helper.ts +0 -32
- package/src/lib/components/code-editor/helpers/r-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/r-helper.ts +0 -32
- package/src/lib/components/code-editor/helpers/ruby-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/ruby-helper.ts +0 -32
- package/src/lib/components/code-editor/helpers/scala-helper.spec.ts +0 -41
- package/src/lib/components/code-editor/helpers/scala-helper.ts +0 -53
- package/src/lib/components/code-editor/helpers/sql-helper.spec.ts +0 -87
- package/src/lib/components/code-editor/helpers/sql-helper.ts +0 -44
- package/src/lib/components/code-editor/helpers/swift-helper.spec.ts +0 -40
- package/src/lib/components/code-editor/helpers/swift-helper.ts +0 -51
- package/src/lib/components/code-editor/helpers/typescript-helper.spec.ts +0 -40
- package/src/lib/components/code-editor/helpers/typescript-helper.ts +0 -52
- package/src/lib/components/code-editor/models/code-editor.model.ts +0 -9
- package/src/lib/components/code-editor/models/coding-snapshot.model.ts +0 -4
- package/src/lib/components/coding-question/coding-question.component.html +0 -78
- package/src/lib/components/coding-question/coding-question.component.scss +0 -76
- package/src/lib/components/coding-question/coding-question.component.spec.ts +0 -85
- package/src/lib/components/coding-question/coding-question.component.ts +0 -102
- package/src/lib/components/coding-section/coding-section.component.html +0 -82
- package/src/lib/components/coding-section/coding-section.component.scss +0 -64
- package/src/lib/components/coding-section/coding-section.component.spec.ts +0 -257
- package/src/lib/components/coding-section/coding-section.component.ts +0 -187
- package/src/lib/components/coding-test.module.ts +0 -124
- package/src/lib/components/common/truncated-text/truncated-text.component.html +0 -6
- package/src/lib/components/common/truncated-text/truncated-text.component.scss +0 -18
- package/src/lib/components/common/truncated-text/truncated-text.component.spec.ts +0 -84
- package/src/lib/components/common/truncated-text/truncated-text.component.ts +0 -37
- package/src/lib/components/configurations/configurations.component.html +0 -57
- package/src/lib/components/configurations/configurations.component.scss +0 -42
- package/src/lib/components/configurations/configurations.component.spec.ts +0 -186
- package/src/lib/components/configurations/configurations.component.ts +0 -98
- package/src/lib/components/instructions/instructions.component.html +0 -41
- package/src/lib/components/instructions/instructions.component.scss +0 -167
- package/src/lib/components/instructions/instructions.component.spec.ts +0 -106
- package/src/lib/components/instructions/instructions.component.ts +0 -138
- package/src/lib/components/panel/panel.component.html +0 -19
- package/src/lib/components/panel/panel.component.scss +0 -41
- package/src/lib/components/panel/panel.component.spec.ts +0 -40
- package/src/lib/components/panel/panel.component.ts +0 -34
- package/src/lib/components/runnable-editor/runnable-editor.component.html +0 -75
- package/src/lib/components/runnable-editor/runnable-editor.component.scss +0 -55
- package/src/lib/components/runnable-editor/runnable-editor.component.spec.ts +0 -124
- package/src/lib/components/runnable-editor/runnable-editor.component.ts +0 -155
- package/src/lib/components/tests/test-cases/test-cases.component.html +0 -135
- package/src/lib/components/tests/test-cases/test-cases.component.scss +0 -220
- package/src/lib/components/tests/test-cases/test-cases.component.spec.ts +0 -401
- package/src/lib/components/tests/test-cases/test-cases.component.ts +0 -205
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.html +0 -94
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.scss +0 -103
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.spec.ts +0 -122
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.ts +0 -102
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.html +0 -16
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.scss +0 -49
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.spec.ts +0 -22
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.ts +0 -18
- package/src/lib/components/tests/test-results.component.html +0 -119
- package/src/lib/components/tests/test-results.component.scss +0 -189
- package/src/lib/components/tests/test-results.component.spec.ts +0 -140
- package/src/lib/components/tests/test-results.component.ts +0 -98
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.html +0 -96
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.scss +0 -6
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.spec.ts +0 -599
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.ts +0 -279
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.html +0 -36
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.scss +0 -183
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.spec.ts +0 -883
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.ts +0 -575
- package/src/lib/config/tgo-coding-test.config.ts +0 -26
- package/src/lib/config/tgo-coding-test.token.ts +0 -21
- package/src/lib/models/.gitkeep +0 -0
- package/src/lib/models/auto-saved-data.ts +0 -51
- package/src/lib/models/code-event.ts +0 -17
- package/src/lib/models/coderunner-execution-results.ts +0 -58
- package/src/lib/models/coding-lib.mocks.ts +0 -246
- package/src/lib/models/configs.ts +0 -18
- package/src/lib/models/language-change-action.ts +0 -4
- package/src/lib/models/lat-languages.ts +0 -12
- package/src/lib/models/mixpanel-events.ts +0 -3
- package/src/lib/models/mode.ts +0 -5
- package/src/lib/models/paste-data.ts +0 -4
- package/src/lib/models/programming-language.ts +0 -9
- package/src/lib/models/test-cases.ts +0 -74
- package/src/lib/models/theme.ts +0 -5
- package/src/lib/models/translations.ts +0 -1
- package/src/lib/models/view-mode.ts +0 -6
- package/src/lib/services/.gitkeep +0 -0
- package/src/lib/services/candidate-coding-test-services/candidature-api.service.spec.ts +0 -40
- package/src/lib/services/candidate-coding-test-services/candidature-api.service.ts +0 -15
- package/src/lib/services/candidate-coding-test-services/coderunner-api.service.spec.ts +0 -134
- package/src/lib/services/candidate-coding-test-services/coderunner-api.service.ts +0 -105
- package/src/lib/services/candidate-coding-test-services/coding-test-tour.service.spec.ts +0 -161
- package/src/lib/services/candidate-coding-test-services/coding-test-tour.service.ts +0 -100
- package/src/lib/services/candidate-coding-test-services/coding-test.service.spec.ts +0 -1524
- package/src/lib/services/candidate-coding-test-services/coding-test.service.ts +0 -843
- package/src/lib/services/coding-test-config.service.ts +0 -48
- package/src/lib/services/configurations.service.mocks.ts +0 -77
- package/src/lib/services/configurations.service.spec.ts +0 -79
- package/src/lib/services/configurations.service.ts +0 -111
- package/src/lib/services/index.ts +0 -0
- package/src/lib/services/lib-coding-test.service.spec.ts +0 -265
- package/src/lib/services/lib-coding-test.service.ts +0 -157
- package/src/lib/services/local-storage.service.mocks.ts +0 -22
- package/src/lib/services/storage.service.spec.ts +0 -1120
- package/src/lib/services/storage.service.ts +0 -729
- package/src/lib/services/test-cases.service.spec.ts +0 -53
- package/src/lib/services/test-cases.service.ts +0 -29
- package/src/lib/services/theme.service.spec.ts +0 -76
- package/src/lib/services/theme.service.ts +0 -34
- package/src/lib/styles/mixins.scss +0 -86
- package/src/lib/styles/styles.scss +0 -112
- package/src/lib/styles/variables.scss +0 -105
- package/src/lib/utils/.gitkeep +0 -0
- package/src/lib/utils/additional-languages/erlang.ts +0 -115
- package/src/lib/utils/resize-element.ts +0 -15
- package/src/lib/utils/time-to-ms.util.ts +0 -10
- package/src/test-setup.ts +0 -1
- package/tsconfig.json +0 -16
- package/tsconfig.lib.json +0 -12
- package/tsconfig.lib.prod.json +0 -9
- package/tsconfig.spec.json +0 -13
- /package/{src/assets → assets}/i18n/en.json +0 -0
- /package/{src/lib/components/code-editor/helpers/index.ts → lib/components/code-editor/helpers/index.d.ts} +0 -0
|
@@ -1,729 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@angular/core';
|
|
2
|
-
import { LocalStorageService } from 'ngx-webstorage';
|
|
3
|
-
import { filter, Subscription } from 'rxjs';
|
|
4
|
-
import { CodeEditorLanguages } from '../components/code-editor/helpers/code-editor-helper.model';
|
|
5
|
-
import { AutoSavedData, AutoSavedDataV1, AutoSavedDataV2, QuestionData, TestData } from '../models/auto-saved-data';
|
|
6
|
-
import { Config } from '../models/configs';
|
|
7
|
-
import { AssessmentIdPreview } from '../models/lat-languages';
|
|
8
|
-
import { Modes } from '../models/mode';
|
|
9
|
-
import { CustomTestCase, ExampleTestCase } from '../models/test-cases';
|
|
10
|
-
import { ConfigurationsService } from './configurations.service';
|
|
11
|
-
import { LibCodingTestService } from './lib-coding-test.service';
|
|
12
|
-
import { timeToMs } from '../utils/time-to-ms.util';
|
|
13
|
-
|
|
14
|
-
@Injectable({
|
|
15
|
-
providedIn: 'root',
|
|
16
|
-
})
|
|
17
|
-
export class StorageCodingService {
|
|
18
|
-
private readonly CURRENT_STORAGE_VERSION = 2;
|
|
19
|
-
private autoSavedData: AutoSavedData = {
|
|
20
|
-
version: this.CURRENT_STORAGE_VERSION,
|
|
21
|
-
config: {} as Config,
|
|
22
|
-
isFullscreen: false,
|
|
23
|
-
assessments: {},
|
|
24
|
-
lastModified: Date.now(),
|
|
25
|
-
};
|
|
26
|
-
private readonly key = 'savedData';
|
|
27
|
-
private assessmentId: string;
|
|
28
|
-
private questionId: string;
|
|
29
|
-
private language: CodeEditorLanguages;
|
|
30
|
-
private codeSaveEnabled: boolean;
|
|
31
|
-
private testCasesSaveEnabled: boolean;
|
|
32
|
-
private isLAT: boolean;
|
|
33
|
-
private currentMode: Modes;
|
|
34
|
-
private isPreview: boolean;
|
|
35
|
-
private codeChangeSubscription: Subscription;
|
|
36
|
-
private configSubscription: Subscription;
|
|
37
|
-
private isFullscreenSubscription: Subscription;
|
|
38
|
-
private currentLanguageSubscription: Subscription;
|
|
39
|
-
private isCodeComponentAlive = filter(() => !this.configurationsService.getCodeComponentDestroyed());
|
|
40
|
-
|
|
41
|
-
// Maximum age of entire storage data in days
|
|
42
|
-
private readonly MAX_STORAGE_AGE_DAYS = 7;
|
|
43
|
-
// Maximum age for assessment inner data in days
|
|
44
|
-
private readonly MAX_QUESTION_DATA_AGE_DAYS = 1;
|
|
45
|
-
// Maximum number of assessments to keep
|
|
46
|
-
private readonly MAX_ASSESSMENTS = 10;
|
|
47
|
-
// The default question ID used for migrated v1 data
|
|
48
|
-
private readonly DEFAULT_MIGRATION_QUESTION_ID = 'default-question';
|
|
49
|
-
|
|
50
|
-
// todo: remove
|
|
51
|
-
// storage = {
|
|
52
|
-
// retrieve: (key: string) => {
|
|
53
|
-
// return {} as any;
|
|
54
|
-
// },
|
|
55
|
-
// store: (key: string, value: any) => {
|
|
56
|
-
// return {} as any;
|
|
57
|
-
// },
|
|
58
|
-
// clear: (key: string) => {
|
|
59
|
-
// return {} as any;
|
|
60
|
-
// },
|
|
61
|
-
// };
|
|
62
|
-
|
|
63
|
-
constructor(
|
|
64
|
-
// todo
|
|
65
|
-
private storage: LocalStorageService,
|
|
66
|
-
private libCodingTestService: LibCodingTestService,
|
|
67
|
-
private configurationsService: ConfigurationsService
|
|
68
|
-
) {
|
|
69
|
-
// Perform safety check on localStorage data
|
|
70
|
-
this.performStorageSafetyCheck();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Performs a safety check on localStorage data.
|
|
75
|
-
* This is called at service initialization to ensure data integrity.
|
|
76
|
-
*/
|
|
77
|
-
private performStorageSafetyCheck(): void {
|
|
78
|
-
try {
|
|
79
|
-
const savedData = this.storage.retrieve(this.key);
|
|
80
|
-
|
|
81
|
-
// If no data, nothing to check
|
|
82
|
-
if (!savedData) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Check storage format and migrate if needed
|
|
87
|
-
if (!('version' in savedData)) {
|
|
88
|
-
// It's v1 format, so we'll migrate it when it's actually needed
|
|
89
|
-
// No need to do anything right now
|
|
90
|
-
} else {
|
|
91
|
-
// It's v2 format, so we can perform cleanup right away
|
|
92
|
-
this.autoSavedData = savedData as AutoSavedData;
|
|
93
|
-
}
|
|
94
|
-
} catch (error) {
|
|
95
|
-
// If any error occurs during safety check, reset storage to avoid issues
|
|
96
|
-
console.error('Error during storage safety check, resetting storage:', error);
|
|
97
|
-
this.autoSavedData = {
|
|
98
|
-
version: this.CURRENT_STORAGE_VERSION,
|
|
99
|
-
config: {} as Config,
|
|
100
|
-
isFullscreen: false,
|
|
101
|
-
assessments: {},
|
|
102
|
-
lastModified: Date.now(),
|
|
103
|
-
};
|
|
104
|
-
this.storeData();
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
initializeSaving(): void {
|
|
109
|
-
if (!this.codeChangeSubscription) {
|
|
110
|
-
this.codeChangeSubscription = this.libCodingTestService.codeChange$
|
|
111
|
-
.pipe(this.isCodeComponentAlive)
|
|
112
|
-
.subscribe((code: string) => {
|
|
113
|
-
if (this.codeSaveEnabled && this.assessmentId && this.questionId) {
|
|
114
|
-
this.ensureDataStructure();
|
|
115
|
-
const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
|
|
116
|
-
const targetTestData = this.isPreview ? questionData.preview : questionData.actual;
|
|
117
|
-
targetTestData.code[this.language] = code!;
|
|
118
|
-
this.updateLastModified(targetTestData);
|
|
119
|
-
this.storeData();
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (!this.configSubscription) {
|
|
125
|
-
this.configSubscription = this.configurationsService.config$
|
|
126
|
-
.pipe(this.isCodeComponentAlive)
|
|
127
|
-
.subscribe((config: Config) => {
|
|
128
|
-
this.autoSavedData.config = { ...config };
|
|
129
|
-
this.updateLastModified(this.autoSavedData);
|
|
130
|
-
this.storeData();
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (!this.isFullscreenSubscription) {
|
|
135
|
-
this.isFullscreenSubscription = this.libCodingTestService.isFullscreen$
|
|
136
|
-
.pipe(this.isCodeComponentAlive)
|
|
137
|
-
.subscribe((isFullscreen: boolean) => {
|
|
138
|
-
this.autoSavedData.isFullscreen = isFullscreen;
|
|
139
|
-
this.updateLastModified(this.autoSavedData);
|
|
140
|
-
this.storeData();
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (!this.currentLanguageSubscription && this.isLAT) {
|
|
145
|
-
this.currentLanguageSubscription = this.libCodingTestService.currentLanguage$
|
|
146
|
-
.pipe(this.isCodeComponentAlive)
|
|
147
|
-
.subscribe((language: CodeEditorLanguages) => {
|
|
148
|
-
this.autoSavedData.lastLanguageLAT = {
|
|
149
|
-
value: language,
|
|
150
|
-
version: this.libCodingTestService.getVersion(),
|
|
151
|
-
};
|
|
152
|
-
this.updateLastModified(this.autoSavedData);
|
|
153
|
-
this.storeData();
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
setupAutoSavedData(
|
|
159
|
-
language: CodeEditorLanguages,
|
|
160
|
-
assessmentId: string,
|
|
161
|
-
questionId: string,
|
|
162
|
-
codeSaveEnabled: boolean,
|
|
163
|
-
testCasesSaveEnabled: boolean,
|
|
164
|
-
isLAT: boolean,
|
|
165
|
-
mode: Modes
|
|
166
|
-
) {
|
|
167
|
-
this.language = language;
|
|
168
|
-
this.assessmentId = assessmentId;
|
|
169
|
-
this.questionId = questionId;
|
|
170
|
-
this.codeSaveEnabled = codeSaveEnabled;
|
|
171
|
-
this.testCasesSaveEnabled = testCasesSaveEnabled;
|
|
172
|
-
this.isLAT = isLAT;
|
|
173
|
-
this.currentMode = mode;
|
|
174
|
-
this.isPreview = mode === Modes.Preview || mode === Modes.NonAssessmentPreview;
|
|
175
|
-
|
|
176
|
-
// Get saved data
|
|
177
|
-
const savedData = this.storage.retrieve(this.key);
|
|
178
|
-
|
|
179
|
-
// Handle migration if needed
|
|
180
|
-
if (savedData) {
|
|
181
|
-
// Check if it's v1 schema (no version field)
|
|
182
|
-
if (!('version' in savedData)) {
|
|
183
|
-
this.migrateFromV1ToV2(savedData as AutoSavedDataV1);
|
|
184
|
-
} else {
|
|
185
|
-
this.autoSavedData = savedData as AutoSavedData;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Apply loaded config and fullscreen setting
|
|
189
|
-
this.configurationsService.setConfig(this.autoSavedData.config);
|
|
190
|
-
this.libCodingTestService.setFullscreen(this.autoSavedData.isFullscreen);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
private migrateFromV1ToV2(v1Data: AutoSavedDataV1): void {
|
|
195
|
-
// Create a new v2 data structure
|
|
196
|
-
const v2Data: AutoSavedDataV2 = {
|
|
197
|
-
version: this.CURRENT_STORAGE_VERSION,
|
|
198
|
-
config: v1Data.config,
|
|
199
|
-
isFullscreen: v1Data.isFullscreen,
|
|
200
|
-
lastLanguageLAT: v1Data.lastLanguageLAT,
|
|
201
|
-
assessments: {},
|
|
202
|
-
lastModified: Date.now(),
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
// Migrate assessment data
|
|
206
|
-
// In v1, assessments were directly mapped to TestData
|
|
207
|
-
// In v2, we need to organize by questionId
|
|
208
|
-
for (const [assessmentId, testData] of Object.entries(v1Data.assessments)) {
|
|
209
|
-
if (assessmentId === AssessmentIdPreview) {
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// We use a consistent default questionId for migration to ensure backward compatibility
|
|
214
|
-
const defaultQuestionId = this.DEFAULT_MIGRATION_QUESTION_ID;
|
|
215
|
-
|
|
216
|
-
// Initialize the assessment entry if it doesn't exist
|
|
217
|
-
if (!v2Data.assessments[assessmentId]) {
|
|
218
|
-
v2Data.assessments[assessmentId] = {};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Create question data with the migrated test data
|
|
222
|
-
const questionData: QuestionData = {};
|
|
223
|
-
|
|
224
|
-
questionData.actual = {
|
|
225
|
-
...testData,
|
|
226
|
-
lastModified: Date.now(),
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
// Set last modified time for the question data
|
|
230
|
-
questionData.lastModified = Date.now();
|
|
231
|
-
|
|
232
|
-
// Add to the v2 structure
|
|
233
|
-
v2Data.assessments[assessmentId][defaultQuestionId] = questionData;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Update our instance with migrated data
|
|
237
|
-
this.autoSavedData = { ...v2Data };
|
|
238
|
-
|
|
239
|
-
// Save the migrated data
|
|
240
|
-
this.storeData();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
private ensureDataStructure(): void {
|
|
244
|
-
// Make sure assessment exists
|
|
245
|
-
if (!this.autoSavedData.assessments[this.assessmentId]) {
|
|
246
|
-
this.autoSavedData.assessments[this.assessmentId] = {};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Make sure question exists
|
|
250
|
-
if (!this.autoSavedData.assessments[this.assessmentId][this.questionId]) {
|
|
251
|
-
this.autoSavedData.assessments[this.assessmentId][this.questionId] = {
|
|
252
|
-
lastModified: Date.now(),
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
|
|
257
|
-
|
|
258
|
-
// Ensure preview or actual exists based on current mode
|
|
259
|
-
if (this.isPreview && !questionData.preview) {
|
|
260
|
-
questionData.preview = {
|
|
261
|
-
code: {},
|
|
262
|
-
testCasesLAT: [],
|
|
263
|
-
lastModified: Date.now(),
|
|
264
|
-
};
|
|
265
|
-
} else if (!this.isPreview && !questionData.actual) {
|
|
266
|
-
questionData.actual = {
|
|
267
|
-
code: {},
|
|
268
|
-
testCasesLAT: [],
|
|
269
|
-
lastModified: Date.now(),
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
private updateLastModified(data: TestData | QuestionData | AutoSavedData): void {
|
|
275
|
-
const now = Date.now();
|
|
276
|
-
data.lastModified = now;
|
|
277
|
-
|
|
278
|
-
// If updating a TestData, also update its parent QuestionData
|
|
279
|
-
if ('code' in data && this.assessmentId && this.questionId) {
|
|
280
|
-
this.autoSavedData.assessments[this.assessmentId][this.questionId].lastModified = now;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Always update root timestamp regardless of the object being modified
|
|
284
|
-
this.autoSavedData.lastModified = now;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Cleanup with a temporary age threshold
|
|
289
|
-
* @param maxAgeDays Maximum age in days for data to be considered valid
|
|
290
|
-
*/
|
|
291
|
-
private cleanupWithReducedThreshold(maxAgeDays: number): void {
|
|
292
|
-
// Call the unified cleanup method with more aggressive parameters
|
|
293
|
-
this.cleanupStorageData({
|
|
294
|
-
storageAgeMultiplier: 2, // More aggressive multiplier
|
|
295
|
-
customStorageAgeDays: maxAgeDays, // Use the provided custom age
|
|
296
|
-
minQuestionDataAgeDays: 0.5, // 12 hours minimum
|
|
297
|
-
assessmentLimitMultiplier: 0.5, // Half the normal assessment limit
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Unified method to clean up localStorage data with configurable intensity
|
|
303
|
-
* @param options Cleanup options to control the aggressiveness of the cleanup
|
|
304
|
-
*/
|
|
305
|
-
private cleanupStorageData(options: {
|
|
306
|
-
storageAgeMultiplier?: number; // Multiplier for storage age threshold (default: 1)
|
|
307
|
-
customStorageAgeDays?: number; // Custom storage age in days (overrides MAX_STORAGE_AGE_DAYS if provided)
|
|
308
|
-
useStandardQuestionDataAge?: boolean; // Whether to use standard question data age (default: false)
|
|
309
|
-
minQuestionDataAgeDays?: number; // Minimum age for question data in days (default: 0.5 - 12 hours)
|
|
310
|
-
assessmentLimitMultiplier?: number; // Multiplier for maximum assessments (default: 1)
|
|
311
|
-
}): void {
|
|
312
|
-
const now = Date.now();
|
|
313
|
-
|
|
314
|
-
// Determine the storage age threshold
|
|
315
|
-
const storageAgeDays = options.customStorageAgeDays ?? this.MAX_STORAGE_AGE_DAYS;
|
|
316
|
-
const storageAgeThreshold = timeToMs(storageAgeDays); // Convert days to milliseconds
|
|
317
|
-
const multiplier = options.storageAgeMultiplier ?? 1;
|
|
318
|
-
|
|
319
|
-
// Check if the entire storage is too old and needs cleanup
|
|
320
|
-
if (this.autoSavedData.lastModified && now - this.autoSavedData.lastModified > storageAgeThreshold * multiplier) {
|
|
321
|
-
// If the entire storage is very old, just reset everything
|
|
322
|
-
this.autoSavedData = {
|
|
323
|
-
version: this.CURRENT_STORAGE_VERSION,
|
|
324
|
-
config: this.autoSavedData.config, // Keep the config settings
|
|
325
|
-
isFullscreen: this.autoSavedData.isFullscreen, // Keep fullscreen setting
|
|
326
|
-
assessments: {},
|
|
327
|
-
lastModified: now,
|
|
328
|
-
};
|
|
329
|
-
this.storeData();
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Structure for collecting assessment data with metadata
|
|
334
|
-
interface AssessmentMetadata {
|
|
335
|
-
id: string;
|
|
336
|
-
lastModified: number;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const assessmentMetadata: AssessmentMetadata[] = [];
|
|
340
|
-
|
|
341
|
-
// Determine the question data age threshold
|
|
342
|
-
let questionDataAgeThreshold: number;
|
|
343
|
-
if (options.useStandardQuestionDataAge) {
|
|
344
|
-
// Use the standard threshold for normal cleanup
|
|
345
|
-
questionDataAgeThreshold = timeToMs(this.MAX_QUESTION_DATA_AGE_DAYS);
|
|
346
|
-
} else {
|
|
347
|
-
// For maintenance/aggressive cleanup, use a custom threshold
|
|
348
|
-
const minAgeHours = (options.minQuestionDataAgeDays ?? 0.5) * 24; // Convert days to hours
|
|
349
|
-
questionDataAgeThreshold = Math.max(
|
|
350
|
-
timeToMs(this.MAX_QUESTION_DATA_AGE_DAYS), // Standard age in milliseconds
|
|
351
|
-
timeToMs(minAgeHours, 'hours') // Minimum age in milliseconds
|
|
352
|
-
);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Collect assessments with their latest modification times
|
|
356
|
-
for (const [assessmentId, questions] of Object.entries(this.autoSavedData.assessments)) {
|
|
357
|
-
let assessmentLastModified = 0;
|
|
358
|
-
|
|
359
|
-
// Check all questions in this assessment
|
|
360
|
-
let hasValidQuestions = false;
|
|
361
|
-
|
|
362
|
-
for (const [questionId, questionData] of Object.entries(questions)) {
|
|
363
|
-
// Skip if undefined
|
|
364
|
-
if (!questionData) {
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// Get the latest modification time from preview and actual
|
|
369
|
-
const previewTime = questionData.preview?.lastModified || 0;
|
|
370
|
-
const actualTime = questionData.actual?.lastModified || 0;
|
|
371
|
-
const questionLastModified = Math.max(previewTime, actualTime, questionData.lastModified || 0);
|
|
372
|
-
|
|
373
|
-
// Check if data is too old - using configured threshold
|
|
374
|
-
const isPreviewTooOld = previewTime > 0 && now - previewTime > questionDataAgeThreshold;
|
|
375
|
-
const isActualTooOld = actualTime > 0 && now - actualTime > questionDataAgeThreshold;
|
|
376
|
-
|
|
377
|
-
// Clean up old data within the question
|
|
378
|
-
if (isPreviewTooOld && questionData.preview) {
|
|
379
|
-
delete questionData.preview;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (isActualTooOld && questionData.actual) {
|
|
383
|
-
delete questionData.actual;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// If neither preview nor actual exists, remove the question
|
|
387
|
-
if (!questionData.preview && !questionData.actual) {
|
|
388
|
-
delete questions[questionId];
|
|
389
|
-
} else {
|
|
390
|
-
hasValidQuestions = true;
|
|
391
|
-
assessmentLastModified = Math.max(assessmentLastModified, questionLastModified);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// If no valid questions, remove the assessment
|
|
396
|
-
if (!hasValidQuestions) {
|
|
397
|
-
delete this.autoSavedData.assessments[assessmentId];
|
|
398
|
-
} else {
|
|
399
|
-
// Add to our list for potential size-based cleanup
|
|
400
|
-
assessmentMetadata.push({
|
|
401
|
-
id: assessmentId,
|
|
402
|
-
lastModified: assessmentLastModified,
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Determine the assessment limit based on the multiplier
|
|
408
|
-
const limitMultiplier = options.assessmentLimitMultiplier ?? 1;
|
|
409
|
-
const assessmentLimit = Math.ceil(this.MAX_ASSESSMENTS * limitMultiplier);
|
|
410
|
-
|
|
411
|
-
// If we have too many assessments, remove the oldest ones
|
|
412
|
-
if (assessmentMetadata.length > assessmentLimit) {
|
|
413
|
-
// Sort by lastModified (most recent first)
|
|
414
|
-
assessmentMetadata.sort((a, b) => b.lastModified - a.lastModified);
|
|
415
|
-
|
|
416
|
-
// Remove oldest assessments that exceed our limit
|
|
417
|
-
for (let i = assessmentLimit; i < assessmentMetadata.length; i++) {
|
|
418
|
-
delete this.autoSavedData.assessments[assessmentMetadata[i].id];
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// Save the cleaned data
|
|
423
|
-
this.storeData();
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
changeLanguage(language: CodeEditorLanguages) {
|
|
427
|
-
this.language = language;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Gets data from v1 schema format
|
|
432
|
-
* Used for backward compatibility when retrieving data
|
|
433
|
-
*/
|
|
434
|
-
private getDataFromV1Schema(retrievedData: AutoSavedDataV1): string | (ExampleTestCase | CustomTestCase)[] | null | undefined {
|
|
435
|
-
// For v1, we need to handle the case where we don't have questionId
|
|
436
|
-
// We're now using questionId in the app, but stored data might still be in v1 format
|
|
437
|
-
|
|
438
|
-
// For preview data, the assessment ID would be AssessmentIdPreview
|
|
439
|
-
if (this.assessmentId === AssessmentIdPreview) {
|
|
440
|
-
if (this.isPreview) {
|
|
441
|
-
// For preview mode on preview assessment, get the code directly
|
|
442
|
-
const code = retrievedData.assessments[this.assessmentId]?.code;
|
|
443
|
-
if (code && this.language in code) {
|
|
444
|
-
return code[this.language];
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
// We don't expect actual/non-preview data for AssessmentIdPreview
|
|
448
|
-
return null;
|
|
449
|
-
} else {
|
|
450
|
-
// For regular assessments, v1 only had code in the "actual" section
|
|
451
|
-
if (!this.isPreview) {
|
|
452
|
-
const code = retrievedData.assessments[this.assessmentId]?.code;
|
|
453
|
-
if (code && this.language in code) {
|
|
454
|
-
return code[this.language];
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
// We don't have preview data for regular assessments in v1
|
|
458
|
-
return null;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
getSavedCode(): string | null | undefined {
|
|
463
|
-
const retrievedData = this.retrieveData();
|
|
464
|
-
if (!retrievedData) {
|
|
465
|
-
return null;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
// Check if using v2 schema
|
|
469
|
-
if ('version' in retrievedData) {
|
|
470
|
-
// Handle v2 schema
|
|
471
|
-
const v2Data = retrievedData;
|
|
472
|
-
const assessmentData = v2Data.assessments[this.assessmentId];
|
|
473
|
-
|
|
474
|
-
if (!assessmentData) {
|
|
475
|
-
return null;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// First try with provided questionId
|
|
479
|
-
if (this.questionId && assessmentData[this.questionId]) {
|
|
480
|
-
const questionData = assessmentData[this.questionId];
|
|
481
|
-
const testData = this.isPreview ? questionData.preview : questionData.actual;
|
|
482
|
-
if (testData?.code && this.language in testData.code) {
|
|
483
|
-
return testData.code[this.language];
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
if (
|
|
488
|
-
this.questionId !== this.DEFAULT_MIGRATION_QUESTION_ID &&
|
|
489
|
-
assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID]
|
|
490
|
-
) {
|
|
491
|
-
const questionData = assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID];
|
|
492
|
-
const testData = this.isPreview ? questionData.preview : questionData.actual;
|
|
493
|
-
if (testData?.code && this.language in testData.code) {
|
|
494
|
-
return testData.code[this.language];
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
return null;
|
|
499
|
-
} else {
|
|
500
|
-
// Handle v1 schema for backward compatibility
|
|
501
|
-
return this.getDataFromV1Schema(retrievedData) as string;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
getLastLanguageLAT(): {
|
|
506
|
-
value: CodeEditorLanguages;
|
|
507
|
-
version: string;
|
|
508
|
-
} | null {
|
|
509
|
-
const retrievedData = this.retrieveData();
|
|
510
|
-
if (!retrievedData) {
|
|
511
|
-
return null;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
return retrievedData.lastLanguageLAT || null;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
getSavedTestCases(): (ExampleTestCase | CustomTestCase)[] | null | undefined {
|
|
518
|
-
const retrievedData = this.retrieveData();
|
|
519
|
-
if (!retrievedData) {
|
|
520
|
-
return null;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
// Check if using v2 schema
|
|
524
|
-
if ('version' in retrievedData) {
|
|
525
|
-
// Handle v2 schema
|
|
526
|
-
const v2Data = retrievedData;
|
|
527
|
-
const assessmentData = v2Data.assessments[this.assessmentId];
|
|
528
|
-
|
|
529
|
-
if (!assessmentData) {
|
|
530
|
-
return null;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// First try with provided questionId
|
|
534
|
-
if (this.questionId && assessmentData[this.questionId]) {
|
|
535
|
-
const questionData = assessmentData[this.questionId];
|
|
536
|
-
const testData = this.isPreview ? questionData.preview : questionData.actual;
|
|
537
|
-
if (testData?.testCasesLAT) {
|
|
538
|
-
return testData.testCasesLAT;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// If not found and questionId != DEFAULT_MIGRATION_QUESTION_ID,
|
|
543
|
-
// also try with the default migration ID as a fallback
|
|
544
|
-
if (
|
|
545
|
-
this.questionId !== this.DEFAULT_MIGRATION_QUESTION_ID &&
|
|
546
|
-
assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID]
|
|
547
|
-
) {
|
|
548
|
-
const questionData = assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID];
|
|
549
|
-
const testData = this.isPreview ? questionData.preview : questionData.actual;
|
|
550
|
-
if (testData?.testCasesLAT) {
|
|
551
|
-
return testData.testCasesLAT;
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
return null;
|
|
556
|
-
} else {
|
|
557
|
-
// Handle v1 schema test cases (test cases were only in the actual mode)
|
|
558
|
-
const v1Data = retrievedData;
|
|
559
|
-
if (!this.isPreview && v1Data.assessments[this.assessmentId]?.testCasesLAT) {
|
|
560
|
-
return v1Data.assessments[this.assessmentId].testCasesLAT;
|
|
561
|
-
}
|
|
562
|
-
return null;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
getSavedConfig(): Config | null {
|
|
567
|
-
const retrievedData = this.retrieveData();
|
|
568
|
-
return retrievedData?.config ? { ...retrievedData.config } : null;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
getSavedFullScreenMode(): boolean | null {
|
|
572
|
-
const retrievedData = this.retrieveData();
|
|
573
|
-
return retrievedData?.isFullscreen !== undefined ? retrievedData.isFullscreen : null;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
clearSavedCode(): void {
|
|
577
|
-
this.ensureDataStructure();
|
|
578
|
-
const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
|
|
579
|
-
const targetTestData = this.isPreview ? [questionData.preview] : [questionData.preview, questionData.actual];
|
|
580
|
-
|
|
581
|
-
let hasChanged = false;
|
|
582
|
-
targetTestData.forEach(testData => {
|
|
583
|
-
if (testData) {
|
|
584
|
-
testData.code = {};
|
|
585
|
-
this.updateLastModified(testData);
|
|
586
|
-
hasChanged = true;
|
|
587
|
-
}
|
|
588
|
-
});
|
|
589
|
-
if (hasChanged) {
|
|
590
|
-
this.storeData();
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
clearLastLang(): void {
|
|
595
|
-
this.autoSavedData.lastLanguageLAT = null;
|
|
596
|
-
this.updateLastModified(this.autoSavedData);
|
|
597
|
-
this.storeData();
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
clearSavedTestCases(): void {
|
|
601
|
-
this.ensureDataStructure();
|
|
602
|
-
const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
|
|
603
|
-
const targetTestData = this.isPreview ? questionData.preview : questionData.actual;
|
|
604
|
-
|
|
605
|
-
if (targetTestData) {
|
|
606
|
-
const hasNoCode = !Object.keys(targetTestData.code ?? {}).length;
|
|
607
|
-
|
|
608
|
-
if (this.isPreview) {
|
|
609
|
-
targetTestData.testCasesLAT = [];
|
|
610
|
-
this.updateLastModified(targetTestData);
|
|
611
|
-
} else if (hasNoCode) {
|
|
612
|
-
const allQuestions = this.autoSavedData.assessments[this.assessmentId];
|
|
613
|
-
delete allQuestions[this.questionId];
|
|
614
|
-
this.autoSavedData.assessments[this.assessmentId] = { ...allQuestions };
|
|
615
|
-
this.updateLastModified(this.autoSavedData);
|
|
616
|
-
}
|
|
617
|
-
this.storeData();
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
updateVersion(version: string): void {
|
|
622
|
-
if (this.autoSavedData.lastLanguageLAT) {
|
|
623
|
-
this.autoSavedData.lastLanguageLAT.version = version;
|
|
624
|
-
this.updateLastModified(this.autoSavedData);
|
|
625
|
-
this.storeData();
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
updateTestCases(testCases: (ExampleTestCase | CustomTestCase)[]) {
|
|
630
|
-
if (this.assessmentId && this.questionId && this.testCasesSaveEnabled) {
|
|
631
|
-
this.ensureDataStructure();
|
|
632
|
-
const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
|
|
633
|
-
const targetTestData = this.isPreview ? questionData.preview : questionData.actual;
|
|
634
|
-
|
|
635
|
-
if (targetTestData) {
|
|
636
|
-
targetTestData.testCasesLAT = testCases;
|
|
637
|
-
this.updateLastModified(targetTestData);
|
|
638
|
-
this.storeData();
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
private storeData(): void {
|
|
644
|
-
this.storage.store(this.key, this.autoSavedData);
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
private retrieveData(): AutoSavedData | AutoSavedDataV1 {
|
|
648
|
-
return this.storage.retrieve(this.key) as AutoSavedData | AutoSavedDataV1;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
/**
|
|
652
|
-
* Manually triggers data cleanup and migration.
|
|
653
|
-
* Useful for handling large localStorage or migration when needed.
|
|
654
|
-
* This can be called from application startup or after major events.
|
|
655
|
-
*/
|
|
656
|
-
performMaintenanceAndCleanup(): void {
|
|
657
|
-
// Get current data
|
|
658
|
-
const savedData = this.storage.retrieve(this.key);
|
|
659
|
-
|
|
660
|
-
// If no data, nothing to do
|
|
661
|
-
if (!savedData) {
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
// Check if migration needed
|
|
666
|
-
if (!('version' in savedData)) {
|
|
667
|
-
this.migrateFromV1ToV2(savedData as AutoSavedDataV1);
|
|
668
|
-
} else {
|
|
669
|
-
// Already migrated, just perform cleanup
|
|
670
|
-
this.autoSavedData = savedData as AutoSavedData;
|
|
671
|
-
|
|
672
|
-
// Perform a more aggressive cleanup for manual maintenance
|
|
673
|
-
// by temporarily modifying the cleanup thresholds
|
|
674
|
-
const originalMaxAge = this.MAX_STORAGE_AGE_DAYS;
|
|
675
|
-
const halfAge = Math.floor(originalMaxAge / 2); // Cut threshold in half
|
|
676
|
-
|
|
677
|
-
// Create a custom cleanup function with reduced threshold
|
|
678
|
-
this.cleanupWithReducedThreshold(halfAge);
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// Verify localStorage size is manageable
|
|
682
|
-
try {
|
|
683
|
-
const serializedData = JSON.stringify(this.autoSavedData);
|
|
684
|
-
const sizeInKB = Math.round(serializedData.length / 1024);
|
|
685
|
-
|
|
686
|
-
// If data is too large (over 2MB), perform more aggressive cleanup
|
|
687
|
-
if (sizeInKB > 2048) {
|
|
688
|
-
console.warn(`Local storage data is large (${sizeInKB}KB), performing deep cleanup`);
|
|
689
|
-
|
|
690
|
-
// Use extremely aggressive cleanup settings
|
|
691
|
-
this.cleanupStorageData({
|
|
692
|
-
storageAgeMultiplier: 0.5, // Even more aggressive - half the normal age
|
|
693
|
-
minQuestionDataAgeDays: 0.25, // 6 hours minimum
|
|
694
|
-
assessmentLimitMultiplier: 0.2, // Keep only 20% of assessments
|
|
695
|
-
});
|
|
696
|
-
|
|
697
|
-
// If still too large, keep only a few most recent assessments
|
|
698
|
-
const newSerializedData = JSON.stringify(this.autoSavedData);
|
|
699
|
-
const newSizeInKB = Math.round(newSerializedData.length / 1024);
|
|
700
|
-
|
|
701
|
-
if (newSizeInKB > 1024) {
|
|
702
|
-
// Keep only recent assessments
|
|
703
|
-
const assessments = this.autoSavedData.assessments;
|
|
704
|
-
// Find the newest timestamp in each assessment
|
|
705
|
-
const getNewestTimestamp = (obj: Record<string, QuestionData>) =>
|
|
706
|
-
Object.values(obj).reduce((max, questionData) => Math.max(max, questionData?.lastModified || 0), 0);
|
|
707
|
-
const entries = Object.entries(assessments).sort(
|
|
708
|
-
([, a], [, b]) =>
|
|
709
|
-
getNewestTimestamp(b as Record<string, QuestionData>) -
|
|
710
|
-
getNewestTimestamp(a as Record<string, QuestionData>)
|
|
711
|
-
);
|
|
712
|
-
|
|
713
|
-
// Keep only the 5 most recent assessments
|
|
714
|
-
const keepCount = Math.min(5, entries.length);
|
|
715
|
-
this.autoSavedData.assessments = {};
|
|
716
|
-
|
|
717
|
-
for (let i = 0; i < keepCount; i++) {
|
|
718
|
-
const [id, data] = entries[i];
|
|
719
|
-
this.autoSavedData.assessments[id] = data as Record<string, QuestionData>;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
this.storeData();
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
} catch (error) {
|
|
726
|
-
console.error('Error checking localStorage size', error);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
}
|