diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9ab25d6..a0b8f7a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,8 @@ on: push: branches: - main + - develop + - main-hotfix pull_request: {} jobs: tests: diff --git a/.github/workflows/make_release_pr.yml b/.github/workflows/make_release_pr.yml index 4c0890c1..9a4528b9 100644 --- a/.github/workflows/make_release_pr.yml +++ b/.github/workflows/make_release_pr.yml @@ -18,9 +18,9 @@ jobs: owner: frappe repo: lms title: |- - "chore: merge 'develop' into 'main'" + "chore: merge 'main-hotfix' into 'main'" body: "Automated weekly release" base: main - head: develop + head: main-hotfix env: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index e053c9b8..111c5918 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -4,7 +4,10 @@ on: pull_request: workflow_dispatch: push: - branches: [ main ] + branches: + - main + - develop + - main-hotfix permissions: # Do not change this as GITHUB_TOKEN is being used by roulette diff --git a/.gitignore b/.gitignore index e6c74964..c532a8dc 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ package-lock.json lms/public/frontend lms/www/lms.html lms/www/_lms.html -frappe-ui \ No newline at end of file +frappe-ui +frappe-semgrep-rules \ No newline at end of file diff --git a/.mergify.yml b/.mergify.yml new file mode 100644 index 00000000..098cfd0a --- /dev/null +++ b/.mergify.yml @@ -0,0 +1,30 @@ +pull_request_rules: + - name: backport to develop + conditions: + - label="backport develop" + actions: + backport: + branches: + - develop + assignees: + - "{{ author }}" + + - name: backport to main-hotfix + conditions: + - label="backport main-hotfix" + actions: + backport: + branches: + - main-hotfix + assignees: + - "{{ author }}" + + - name: backport to main + conditions: + - label="backport main" + actions: + backport: + branches: + - main + assignees: + - "{{ author }}" diff --git a/cypress/e2e/batch_creation.cy.js b/cypress/e2e/batch_creation.cy.js index 4f48bf70..653a70a2 100644 --- a/cypress/e2e/batch_creation.cy.js +++ b/cypress/e2e/batch_creation.cy.js @@ -162,8 +162,12 @@ describe("Batch Creation", () => { /* Add student to batch */ cy.get("button").contains("Students").click(); cy.get("button").contains("Add").click(); - cy.get('div[role="dialog"]').first().find("button").eq(1).click(); - cy.get("input[id^='headlessui-combobox-input-v-']").type(randomEmail); + cy.get('div[role="dialog"]') + .first() + .find("input[id^='headlessui-combobox-input-v-']") + .first() + .click(); + cy.get("input[placeholder='Search']").type(randomEmail); cy.get("div").contains(randomEmail).click(); cy.get("button").contains("Submit").click(); diff --git a/cypress/e2e/course_creation.cy.js b/cypress/e2e/course_creation.cy.js index 47a592d9..de0113fe 100644 --- a/cypress/e2e/course_creation.cy.js +++ b/cypress/e2e/course_creation.cy.js @@ -65,7 +65,7 @@ describe("Course Creation", () => { .contains("Category") .parent() .within(() => { - cy.get("button").click(); + cy.get("input").click(); }); cy.get("[id^=headlessui-combobox-option-") .should("be.visible") diff --git a/frappe-semgrep-rules b/frappe-semgrep-rules deleted file mode 160000 index 239029b7..00000000 --- a/frappe-semgrep-rules +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 239029b7ebaf2ec0e83222ca8bc668c8c76668f9 diff --git a/frontend/src/components/Controls/Autocomplete.vue b/frontend/src/components/Controls/Autocomplete.vue index dee1268f..79fbd5b7 100644 --- a/frontend/src/components/Controls/Autocomplete.vue +++ b/frontend/src/components/Controls/Autocomplete.vue @@ -1,137 +1,92 @@ @@ -142,15 +97,16 @@ import { ComboboxInput, ComboboxOptions, ComboboxOption, + ComboboxButton, } from '@headlessui/vue' -import { Popover } from 'frappe-ui' -import { ChevronDown, X } from 'lucide-vue-next' import { ref, computed, useAttrs, useSlots, watch, nextTick } from 'vue' +import { ChevronDown, X } from 'lucide-vue-next' +import { watchDebounced } from '@vueuse/core' const props = defineProps({ modelValue: { - type: String, - default: '', + type: [String, Object], + default: null, }, options: { type: Array, @@ -181,107 +137,93 @@ const props = defineProps({ default: true, }, }) + const emit = defineEmits(['update:modelValue', 'update:query', 'change']) - -const query = ref('') -const showOptions = ref(false) +const trigger = ref(null) const search = ref(null) - const attrs = useAttrs() const slots = useSlots() - +const selectedValue = ref(props.modelValue) +const query = ref('') const valuePropPassed = computed(() => 'value' in attrs) -const selectedValue = computed({ - get() { - return valuePropPassed.value ? attrs.value : props.modelValue - }, - set(val) { - query.value = '' - if (val) { - showOptions.value = false - } - emit(valuePropPassed.value ? 'change' : 'update:modelValue', val) - }, +watch(selectedValue, (val) => { + query.value = '' + emit(valuePropPassed.value ? 'change' : 'update:modelValue', val) }) -function close() { - showOptions.value = false +function clearValue() { + emit('update:modelValue', null) } const groups = computed(() => { - if (!props.options || props.options.length == 0) return [] + if (!props.options?.length) return [] - let groups = props.options[0]?.group + const normalized = props.options[0]?.group ? props.options : [{ group: '', items: props.options }] - - return groups - .map((group, i) => { - return { - key: i, - group: group.group, - hideLabel: group.hideLabel || false, - items: props.filterable ? filterOptions(group.items) : group.items, - } - }) + return normalized + .map((group, i) => ({ + key: i, + group: group.group, + hideLabel: group.hideLabel || false, + items: props.filterable ? filterOptions(group.items) : group.items, + })) .filter((group) => group.items.length > 0) }) function filterOptions(options) { - if (!query.value) { - return options - } - return options.filter((option) => { - let searchTexts = [option.label, option.value] - return searchTexts.some((text) => - (text || '').toString().toLowerCase().includes(query.value.toLowerCase()) - ) + if (!query.value) return options + const q = query.value.toLowerCase() + return options.filter((option) => + [option.label, option.value] + .filter(Boolean) + .some((text) => text.toString().toLowerCase().includes(q)) + ) +} + +watchDebounced( + query, + (val) => { + emit('update:query', val) + }, + { debounce: 300 } +) + +const onFocus = () => { + trigger.value?.$el.click() + nextTick(() => { + search.value?.focus() }) } -function displayValue(option) { - if (typeof option === 'string') { - let allOptions = groups.value.flatMap((group) => group.items) - let selectedOption = allOptions.find((o) => o.value === option) - return selectedOption?.label || option - } - return option?.label +const close = () => { + selectedValue.value = null + trigger.value?.$el.click() } -watch(query, (q) => { - emit('update:query', q) -}) - -watch(showOptions, (val) => { - if (val) { - nextTick(() => { - search.value.el.focus() - }) - } -}) - -const textColor = computed(() => { - return props.disabled ? 'text-ink-gray-5' : 'text-ink-gray-8' -}) +const textColor = computed(() => + props.disabled ? 'text-ink-gray-5' : 'text-ink-gray-8' +) const inputClasses = computed(() => { - let sizeClasses = { + const sizeClasses = { sm: 'text-base rounded h-7', md: 'text-base rounded h-8', lg: 'text-lg rounded-md h-10', xl: 'text-xl rounded-md h-10', }[props.size] - let paddingClasses = { + const paddingClasses = { sm: 'py-1.5 px-2', md: 'py-1.5 px-2.5', lg: 'py-1.5 px-3', xl: 'py-1.5 px-3', }[props.size] - let variant = props.disabled ? 'disabled' : props.variant - let variantClasses = { + const variant = props.disabled ? 'disabled' : props.variant + + const variantClasses = { subtle: 'border border-gray-100 bg-surface-gray-2 placeholder-ink-gray-4 hover:border-outline-gray-modals hover:bg-surface-gray-3 focus:bg-surface-white focus:border-outline-gray-4 focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3', outline: @@ -302,6 +244,4 @@ const inputClasses = computed(() => { 'transition-colors w-full', ] }) - -defineExpose({ query }) diff --git a/frontend/src/components/Controls/Link.vue b/frontend/src/components/Controls/Link.vue index 5742a6fe..a84cea4f 100644 --- a/frontend/src/components/Controls/Link.vue +++ b/frontend/src/components/Controls/Link.vue @@ -11,7 +11,6 @@ :size="attrs.size || 'sm'" :variant="attrs.variant" :placeholder="attrs.placeholder" - :filterable="false" :readonly="attrs.readonly" > diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 66c19b11..61aa0e4a 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -24,34 +24,34 @@ jsonpointer "^5.0.0" leven "^3.1.0" -"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.28.6.tgz#72499312ec58b1e2245ba4a4f550c132be4982f7" - integrity sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q== +"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.28.6", "@babel/code-frame@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c" + integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw== dependencies: "@babel/helper-validator-identifier" "^7.28.5" js-tokens "^4.0.0" picocolors "^1.1.1" -"@babel/compat-data@^7.27.7", "@babel/compat-data@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.6.tgz#103f466803fa0f059e82ccac271475470570d74c" - integrity sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg== +"@babel/compat-data@^7.28.6", "@babel/compat-data@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.0.tgz#00d03e8c0ac24dd9be942c5370990cbe1f17d88d" + integrity sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg== "@babel/core@^7.11.1": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.6.tgz#531bf883a1126e53501ba46eb3bb414047af507f" - integrity sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw== + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.0.tgz#5286ad785df7f79d656e88ce86e650d16ca5f322" + integrity sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA== dependencies: - "@babel/code-frame" "^7.28.6" - "@babel/generator" "^7.28.6" + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" "@babel/helper-compilation-targets" "^7.28.6" "@babel/helper-module-transforms" "^7.28.6" "@babel/helpers" "^7.28.6" - "@babel/parser" "^7.28.6" + "@babel/parser" "^7.29.0" "@babel/template" "^7.28.6" - "@babel/traverse" "^7.28.6" - "@babel/types" "^7.28.6" + "@babel/traverse" "^7.29.0" + "@babel/types" "^7.29.0" "@jridgewell/remapping" "^2.3.5" convert-source-map "^2.0.0" debug "^4.1.0" @@ -59,13 +59,13 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1" - integrity sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw== +"@babel/generator@^7.29.0": + version "7.29.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50" + integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw== dependencies: - "@babel/parser" "^7.28.6" - "@babel/types" "^7.28.6" + "@babel/parser" "^7.29.0" + "@babel/types" "^7.29.0" "@jridgewell/gen-mapping" "^0.3.12" "@jridgewell/trace-mapping" "^0.3.28" jsesc "^3.0.2" @@ -77,7 +77,7 @@ dependencies: "@babel/types" "^7.27.3" -"@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.27.2", "@babel/helper-compilation-targets@^7.28.6": +"@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== @@ -110,16 +110,16 @@ regexpu-core "^6.3.1" semver "^6.3.1" -"@babel/helper-define-polyfill-provider@^0.6.5": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz#742ccf1cb003c07b48859fc9fa2c1bbe40e5f753" - integrity sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg== +"@babel/helper-define-polyfill-provider@^0.6.6": + version "0.6.6" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz#714dfe33d8bd710f556df59953720f6eeb6c1a14" + integrity sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA== dependencies: - "@babel/helper-compilation-targets" "^7.27.2" - "@babel/helper-plugin-utils" "^7.27.1" - debug "^4.4.1" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + debug "^4.4.3" lodash.debounce "^4.0.8" - resolve "^1.22.10" + resolve "^1.22.11" "@babel/helper-globals@^7.28.0": version "7.28.0" @@ -142,7 +142,7 @@ "@babel/traverse" "^7.28.6" "@babel/types" "^7.28.6" -"@babel/helper-module-transforms@^7.27.1", "@babel/helper-module-transforms@^7.28.3", "@babel/helper-module-transforms@^7.28.6": +"@babel/helper-module-transforms@^7.27.1", "@babel/helper-module-transforms@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== @@ -221,12 +221,12 @@ "@babel/template" "^7.28.6" "@babel/types" "^7.28.6" -"@babel/parser@^7.28.5", "@babel/parser@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd" - integrity sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ== +"@babel/parser@^7.28.6", "@babel/parser@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.0.tgz#669ef345add7d057e92b7ed15f0bac07611831b6" + integrity sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww== dependencies: - "@babel/types" "^7.28.6" + "@babel/types" "^7.29.0" "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.28.5": version "7.28.5" @@ -301,14 +301,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-async-generator-functions@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.6.tgz#80cb86d3eaa2102e18ae90dd05ab87bdcad3877d" - integrity sha512-9knsChgsMzBV5Yh3kkhrZNxH3oCYAfMBkNNaVN4cP2RVlFPe8wYdwwcnOsAbkdDoV9UjFtOXWrWB52M8W4jNeA== +"@babel/plugin-transform-async-generator-functions@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz#63ed829820298f0bf143d5a4a68fb8c06ffd742f" + integrity sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w== dependencies: "@babel/helper-plugin-utils" "^7.28.6" "@babel/helper-remap-async-to-generator" "^7.27.1" - "@babel/traverse" "^7.28.6" + "@babel/traverse" "^7.29.0" "@babel/plugin-transform-async-to-generator@^7.28.6": version "7.28.6" @@ -392,10 +392,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.28.6.tgz#e0c59ba54f1655dd682f2edf5f101b5910a8f6f3" - integrity sha512-5suVoXjC14lUN6ZL9OLKIHCNVWCrqGqlmEp/ixdXjvgnEl/kauLvvMO/Xw9NyMc95Joj1AeLVPVMvibBgSoFlA== +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz#8014b8a6cfd0e7b92762724443bf0d2400f26df1" + integrity sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.28.5" "@babel/helper-plugin-utils" "^7.28.6" @@ -490,15 +490,15 @@ "@babel/helper-module-transforms" "^7.28.6" "@babel/helper-plugin-utils" "^7.28.6" -"@babel/plugin-transform-modules-systemjs@^7.28.5": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz#7439e592a92d7670dfcb95d0cbc04bd3e64801d2" - integrity sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew== +"@babel/plugin-transform-modules-systemjs@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz#e458a95a17807c415924106a3ff188a3b8dee964" + integrity sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ== dependencies: - "@babel/helper-module-transforms" "^7.28.3" - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/helper-validator-identifier" "^7.28.5" - "@babel/traverse" "^7.28.5" + "@babel/traverse" "^7.29.0" "@babel/plugin-transform-modules-umd@^7.27.1": version "7.27.1" @@ -508,13 +508,13 @@ "@babel/helper-module-transforms" "^7.27.1" "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-named-capturing-groups-regex@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz#f32b8f7818d8fc0cc46ee20a8ef75f071af976e1" - integrity sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng== +"@babel/plugin-transform-named-capturing-groups-regex@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz#a26cd51e09c4718588fc4cce1c5d1c0152102d6a" + integrity sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.27.1" - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-transform-new-target@^7.27.1": version "7.27.1" @@ -602,10 +602,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-regenerator@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.6.tgz#6ca2ed5b76cff87980f96eaacfc2ce833e8e7a1b" - integrity sha512-eZhoEZHYQLL5uc1gS5e9/oTknS0sSSAtd5TkKMUp3J+S/CaUjagc0kOUPsEbDmMeva0nC3WWl4SxVY6+OBuxfw== +"@babel/plugin-transform-regenerator@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz#dec237cec1b93330876d6da9992c4abd42c9d18b" + integrity sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog== dependencies: "@babel/helper-plugin-utils" "^7.28.6" @@ -692,11 +692,11 @@ "@babel/helper-plugin-utils" "^7.28.6" "@babel/preset-env@^7.11.0": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.28.6.tgz#b4586bb59d8c61be6c58997f4912e7ea6bd17178" - integrity sha512-GaTI4nXDrs7l0qaJ6Rg06dtOXTBCG6TMDB44zbqofCIC4PqC7SEvmFFtpxzCDw9W5aJ7RKVshgXTLvLdBFV/qw== + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.29.0.tgz#c55db400c515a303662faaefd2d87e796efa08d0" + integrity sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w== dependencies: - "@babel/compat-data" "^7.28.6" + "@babel/compat-data" "^7.29.0" "@babel/helper-compilation-targets" "^7.28.6" "@babel/helper-plugin-utils" "^7.28.6" "@babel/helper-validator-option" "^7.27.1" @@ -710,7 +710,7 @@ "@babel/plugin-syntax-import-attributes" "^7.28.6" "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" "@babel/plugin-transform-arrow-functions" "^7.27.1" - "@babel/plugin-transform-async-generator-functions" "^7.28.6" + "@babel/plugin-transform-async-generator-functions" "^7.29.0" "@babel/plugin-transform-async-to-generator" "^7.28.6" "@babel/plugin-transform-block-scoped-functions" "^7.27.1" "@babel/plugin-transform-block-scoping" "^7.28.6" @@ -721,7 +721,7 @@ "@babel/plugin-transform-destructuring" "^7.28.5" "@babel/plugin-transform-dotall-regex" "^7.28.6" "@babel/plugin-transform-duplicate-keys" "^7.27.1" - "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.28.6" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.29.0" "@babel/plugin-transform-dynamic-import" "^7.27.1" "@babel/plugin-transform-explicit-resource-management" "^7.28.6" "@babel/plugin-transform-exponentiation-operator" "^7.28.6" @@ -734,9 +734,9 @@ "@babel/plugin-transform-member-expression-literals" "^7.27.1" "@babel/plugin-transform-modules-amd" "^7.27.1" "@babel/plugin-transform-modules-commonjs" "^7.28.6" - "@babel/plugin-transform-modules-systemjs" "^7.28.5" + "@babel/plugin-transform-modules-systemjs" "^7.29.0" "@babel/plugin-transform-modules-umd" "^7.27.1" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.27.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.29.0" "@babel/plugin-transform-new-target" "^7.27.1" "@babel/plugin-transform-nullish-coalescing-operator" "^7.28.6" "@babel/plugin-transform-numeric-separator" "^7.28.6" @@ -748,7 +748,7 @@ "@babel/plugin-transform-private-methods" "^7.28.6" "@babel/plugin-transform-private-property-in-object" "^7.28.6" "@babel/plugin-transform-property-literals" "^7.27.1" - "@babel/plugin-transform-regenerator" "^7.28.6" + "@babel/plugin-transform-regenerator" "^7.29.0" "@babel/plugin-transform-regexp-modifiers" "^7.28.6" "@babel/plugin-transform-reserved-words" "^7.27.1" "@babel/plugin-transform-shorthand-properties" "^7.27.1" @@ -761,10 +761,10 @@ "@babel/plugin-transform-unicode-regex" "^7.27.1" "@babel/plugin-transform-unicode-sets-regex" "^7.28.6" "@babel/preset-modules" "0.1.6-no-external-plugins" - babel-plugin-polyfill-corejs2 "^0.4.14" - babel-plugin-polyfill-corejs3 "^0.13.0" - babel-plugin-polyfill-regenerator "^0.6.5" - core-js-compat "^3.43.0" + babel-plugin-polyfill-corejs2 "^0.4.15" + babel-plugin-polyfill-corejs3 "^0.14.0" + babel-plugin-polyfill-regenerator "^0.6.6" + core-js-compat "^3.48.0" semver "^6.3.1" "@babel/preset-modules@0.1.6-no-external-plugins": @@ -790,23 +790,23 @@ "@babel/parser" "^7.28.6" "@babel/types" "^7.28.6" -"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.5", "@babel/traverse@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.6.tgz#871ddc79a80599a5030c53b1cc48cbe3a5583c2e" - integrity sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg== +"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.5", "@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a" + integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA== dependencies: - "@babel/code-frame" "^7.28.6" - "@babel/generator" "^7.28.6" + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" "@babel/helper-globals" "^7.28.0" - "@babel/parser" "^7.28.6" + "@babel/parser" "^7.29.0" "@babel/template" "^7.28.6" - "@babel/types" "^7.28.6" + "@babel/types" "^7.29.0" debug "^4.3.1" -"@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.5", "@babel/types@^7.28.6", "@babel/types@^7.4.4": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.6.tgz#c3e9377f1b155005bcc4c46020e7e394e13089df" - integrity sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg== +"@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.5", "@babel/types@^7.28.6", "@babel/types@^7.29.0", "@babel/types@^7.4.4": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" + integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== dependencies: "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" @@ -822,9 +822,9 @@ "@lezer/common" "^1.0.0" "@codemirror/commands@6.x", "@codemirror/commands@^6.0.0": - version "6.10.1" - resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.10.1.tgz#a17a48f846947f48150b9670a3de8c4352b69256" - integrity sha512-uWDWFypNdQmz2y1LaNJzK7fL7TYKLeUAU0npEC685OKTF3KcQ2Vu3klIM78D7I6wGhktme0lh3CuQLv0ZCrD9Q== + version "6.10.2" + resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.10.2.tgz#338bf53ab146de7bb26da4a1d32c6a6ff4d36b39" + integrity sha512-vvX1fsih9HledO1c9zdotZYUZnE4xV0m6i3m25s5DIfXofuprk6cRcLUZvSk3CASUbwjQX21tOGbkY2BH8TpnQ== dependencies: "@codemirror/language" "^6.0.0" "@codemirror/state" "^6.4.0" @@ -902,9 +902,9 @@ style-mod "^4.0.0" "@codemirror/lint@^6.0.0": - version "6.9.2" - resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.9.2.tgz#09ed0aedec13381c9e36e1ac5d126027740c3ef4" - integrity sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ== + version "6.9.4" + resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.9.4.tgz#fbe2fdc7a97241cd393df948ec9932c36ffbafd0" + integrity sha512-ABc9vJ8DEmvOWuH26P3i8FpMWPQkduD9Rvba5iwb6O3hxASgclm3T3krGo8NASXkHCidz6b++LWlzWIUfEPSWw== dependencies: "@codemirror/state" "^6.0.0" "@codemirror/view" "^6.35.0" @@ -927,9 +927,9 @@ "@marijn/find-cluster-break" "^1.0.0" "@codemirror/view@6.x", "@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.27.0", "@codemirror/view@^6.35.0", "@codemirror/view@^6.37.0": - version "6.39.11" - resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.39.11.tgz#200aebef2074bfbbb7a3d5f0644c1b560d876b39" - integrity sha512-bWdeR8gWM87l4DB/kYSF9A+dVackzDb/V56Tq7QVrQ7rn86W0rgZFtlL3g3pem6AeGcb9NQNoy3ao4WpW4h5tQ== + version "6.39.14" + resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.39.14.tgz#ebecaee4c76566c3eb61dfe4d6bf386c617de5cf" + integrity sha512-WJcvgHm/6Q7dvGT0YFv/6PSkoc36QlR0VCESS6x9tGsnF1lWLmmYxOgX3HH6v8fo6AvSLgpcs+H0Olre6MKXlg== dependencies: "@codemirror/state" "^6.5.0" crelt "^1.0.6" @@ -1142,19 +1142,19 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== -"@floating-ui/core@^1.7.3": - version "1.7.3" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.3.tgz#462d722f001e23e46d86fd2bd0d21b7693ccb8b7" - integrity sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w== +"@floating-ui/core@^1.7.4": + version "1.7.4" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.4.tgz#4a006a6e01565c0f87ba222c317b056a2cffd2f4" + integrity sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg== dependencies: "@floating-ui/utils" "^0.2.10" -"@floating-ui/dom@^1.6.13", "@floating-ui/dom@^1.6.7", "@floating-ui/dom@^1.7.0", "@floating-ui/dom@^1.7.4": - version "1.7.4" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.4.tgz#ee667549998745c9c3e3e84683b909c31d6c9a77" - integrity sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA== +"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.6.13", "@floating-ui/dom@^1.6.7", "@floating-ui/dom@^1.7.0", "@floating-ui/dom@^1.7.4", "@floating-ui/dom@^1.7.5": + version "1.7.5" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.5.tgz#60bfc83a4d1275b2a90db76bf42ca2a5f2c231c2" + integrity sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg== dependencies: - "@floating-ui/core" "^1.7.3" + "@floating-ui/core" "^1.7.4" "@floating-ui/utils" "^0.2.10" "@floating-ui/utils@^0.2.10": @@ -1163,11 +1163,11 @@ integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ== "@floating-ui/vue@^1.1.0", "@floating-ui/vue@^1.1.6": - version "1.1.9" - resolved "https://registry.yarnpkg.com/@floating-ui/vue/-/vue-1.1.9.tgz#508c386bd3d595247f1dda8dbca00b76fe8fcaf9" - integrity sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ== + version "1.1.10" + resolved "https://registry.yarnpkg.com/@floating-ui/vue/-/vue-1.1.10.tgz#cae3ff9a1410219fc3da6dd6475cc92dd5281488" + integrity sha512-vdf8f6rHnFPPLRsmL4p12wYl+Ux4mOJOkjzKEMYVnwdf7UFdvBtHlLvQyx8iKG5vhPRbDRgZxdtpmyigDPjzYg== dependencies: - "@floating-ui/dom" "^1.7.4" + "@floating-ui/dom" "^1.7.5" "@floating-ui/utils" "^0.2.10" vue-demi ">=0.13.0" @@ -1198,9 +1198,9 @@ integrity sha512-BUdv0cvs4H5ODuwft2Xp4eL8Vmi3LcihK42z0Ft/FbVJZoRioBsxH+LlsBdK4tAie7PqlKGy+1oyOncu1nQ6eA== "@internationalized/date@^3.5.0", "@internationalized/date@^3.5.4": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.10.1.tgz#ca63817feadeffe97f710289b00af229cd8af15c" - integrity sha512-oJrXtQiAXLvT9clCf1K4kxp3eKsQhIaZqxEyowkBcsvZDdZkbWrVmnGknxs5flTD0VGsxrxKgBCZty1EzoiMzA== + version "3.11.0" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.11.0.tgz#68ac4d18060a9eaa8095ca417272948701728302" + integrity sha512-BOx5huLAWhicM9/ZFs84CzP+V3gBW6vlpM02yzsdYC7TGlZJX1OJiEEHcSayF00Z+3jLlm4w79amvSt6RqKN3Q== dependencies: "@swc/helpers" "^0.5.0" @@ -1264,9 +1264,9 @@ integrity sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w== "@lezer/common@^1.0.0", "@lezer/common@^1.0.2", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0", "@lezer/common@^1.2.1", "@lezer/common@^1.3.0", "@lezer/common@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.5.0.tgz#db227b596260189b67ba286387d9dc81fb07c70b" - integrity sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA== + version "1.5.1" + resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.5.1.tgz#6e8c114ff5d36a41148e146a253734d3bb8807d3" + integrity sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw== "@lezer/css@^1.1.0", "@lezer/css@^1.1.7": version "1.3.0" @@ -1312,9 +1312,9 @@ "@lezer/lr" "^1.0.0" "@lezer/lr@^1.0.0", "@lezer/lr@^1.3.0": - version "1.4.7" - resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.4.7.tgz#01a38556652bf73ffbf3af4a88b91e4c056cc6ee" - integrity sha512-wNIFWdSUfX9Jc6ePMzxSPVgTVB4EOfDIwLQLWASyiUdHKaMsiilj9bYiGkGQCKVodd0x6bgQCV207PILGFCF9Q== + version "1.4.8" + resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.4.8.tgz#333de9bc9346057323ff09beb4cda47ccc38a498" + integrity sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA== dependencies: "@lezer/common" "^1.0.0" @@ -1400,130 +1400,130 @@ estree-walker "^1.0.1" picomatch "^2.2.2" -"@rollup/rollup-android-arm-eabi@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.56.0.tgz#067cfcd81f1c1bfd92aefe3ad5ef1523549d5052" - integrity sha512-LNKIPA5k8PF1+jAFomGe3qN3bbIgJe/IlpDBwuVjrDKrJhVWywgnJvflMt/zkbVNLFtF1+94SljYQS6e99klnw== +"@rollup/rollup-android-arm-eabi@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz#add5e608d4e7be55bc3ca3d962490b8b1890e088" + integrity sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg== -"@rollup/rollup-android-arm64@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.56.0.tgz#85e39a44034d7d4e4fee2a1616f0bddb85a80517" - integrity sha512-lfbVUbelYqXlYiU/HApNMJzT1E87UPGvzveGg2h0ktUNlOCxKlWuJ9jtfvs1sKHdwU4fzY7Pl8sAl49/XaEk6Q== +"@rollup/rollup-android-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz#10bd0382b73592beee6e9800a69401a29da625c4" + integrity sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w== -"@rollup/rollup-darwin-arm64@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.56.0.tgz#17d92fe98f2cc277b91101eb1528b7c0b6c00c54" - integrity sha512-EgxD1ocWfhoD6xSOeEEwyE7tDvwTgZc8Bss7wCWe+uc7wO8G34HHCUH+Q6cHqJubxIAnQzAsyUsClt0yFLu06w== +"@rollup/rollup-darwin-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz#1e99ab04c0b8c619dd7bbde725ba2b87b55bfd81" + integrity sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg== -"@rollup/rollup-darwin-x64@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.56.0.tgz#89ae6c66b1451609bd1f297da9384463f628437d" - integrity sha512-1vXe1vcMOssb/hOF8iv52A7feWW2xnu+c8BV4t1F//m9QVLTfNVpEdja5ia762j/UEJe2Z1jAmEqZAK42tVW3g== +"@rollup/rollup-darwin-x64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz#69e741aeb2839d2e8f0da2ce7a33d8bd23632423" + integrity sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w== -"@rollup/rollup-freebsd-arm64@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.56.0.tgz#cdbdb9947b26e76c188a31238c10639347413628" - integrity sha512-bof7fbIlvqsyv/DtaXSck4VYQ9lPtoWNFCB/JY4snlFuJREXfZnm+Ej6yaCHfQvofJDXLDMTVxWscVSuQvVWUQ== +"@rollup/rollup-freebsd-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz#3736c232a999c7bef7131355d83ebdf9651a0839" + integrity sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug== -"@rollup/rollup-freebsd-x64@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.56.0.tgz#9b1458d07b6e040be16ee36d308a2c9520f7f7cc" - integrity sha512-KNa6lYHloW+7lTEkYGa37fpvPq+NKG/EHKM8+G/g9WDU7ls4sMqbVRV78J6LdNuVaeeK5WB9/9VAFbKxcbXKYg== +"@rollup/rollup-freebsd-x64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz#227dcb8f466684070169942bd3998901c9bfc065" + integrity sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q== -"@rollup/rollup-linux-arm-gnueabihf@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.56.0.tgz#1d50ded7c965d5f125f5832c971ad5b287befef7" - integrity sha512-E8jKK87uOvLrrLN28jnAAAChNq5LeCd2mGgZF+fGF5D507WlG/Noct3lP/QzQ6MrqJ5BCKNwI9ipADB6jyiq2A== +"@rollup/rollup-linux-arm-gnueabihf@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz#ba004b30df31b724f99ce66e7128248bea17cb0c" + integrity sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw== -"@rollup/rollup-linux-arm-musleabihf@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.56.0.tgz#53597e319b7e65990d3bc2a5048097384814c179" - integrity sha512-jQosa5FMYF5Z6prEpTCCmzCXz6eKr/tCBssSmQGEeozA9tkRUty/5Vx06ibaOP9RCrW1Pvb8yp3gvZhHwTDsJw== +"@rollup/rollup-linux-arm-musleabihf@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz#6929f3e07be6b6da5991f63c6b68b3e473d0a65a" + integrity sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw== -"@rollup/rollup-linux-arm64-gnu@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.56.0.tgz#597002909dec198ca4bdccb25f043d32db3d6283" - integrity sha512-uQVoKkrC1KGEV6udrdVahASIsaF8h7iLG0U0W+Xn14ucFwi6uS539PsAr24IEF9/FoDtzMeeJXJIBo5RkbNWvQ== +"@rollup/rollup-linux-arm64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz#06e89fd4a25d21fe5575d60b6f913c0e65297bfa" + integrity sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g== -"@rollup/rollup-linux-arm64-musl@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.56.0.tgz#286f0e0f799545ce288bdc5a7c777261fcba3d54" - integrity sha512-vLZ1yJKLxhQLFKTs42RwTwa6zkGln+bnXc8ueFGMYmBTLfNu58sl5/eXyxRa2RarTkJbXl8TKPgfS6V5ijNqEA== +"@rollup/rollup-linux-arm64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz#fddabf395b90990d5194038e6cd8c00156ed8ac0" + integrity sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q== -"@rollup/rollup-linux-loong64-gnu@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.56.0.tgz#1fab07fa1a4f8d3697735b996517f1bae0ba101b" - integrity sha512-FWfHOCub564kSE3xJQLLIC/hbKqHSVxy8vY75/YHHzWvbJL7aYJkdgwD/xGfUlL5UV2SB7otapLrcCj2xnF1dg== +"@rollup/rollup-linux-loong64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz#04c10bb764bbf09a3c1bd90432e92f58d6603c36" + integrity sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA== -"@rollup/rollup-linux-loong64-musl@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.56.0.tgz#efc2cb143d6c067f95205482afb177f78ed9ea3d" - integrity sha512-z1EkujxIh7nbrKL1lmIpqFTc/sr0u8Uk0zK/qIEFldbt6EDKWFk/pxFq3gYj4Bjn3aa9eEhYRlL3H8ZbPT1xvA== +"@rollup/rollup-linux-loong64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz#f2450361790de80581d8687ea19142d8a4de5c0f" + integrity sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw== -"@rollup/rollup-linux-ppc64-gnu@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.56.0.tgz#e8de8bd3463f96b92b7dfb7f151fd80ffe8a937c" - integrity sha512-iNFTluqgdoQC7AIE8Q34R3AuPrJGJirj5wMUErxj22deOcY7XwZRaqYmB6ZKFHoVGqRcRd0mqO+845jAibKCkw== +"@rollup/rollup-linux-ppc64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz#0474f4667259e407eee1a6d38e29041b708f6a30" + integrity sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w== -"@rollup/rollup-linux-ppc64-musl@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.56.0.tgz#8c508fe28a239da83b3a9da75bcf093186e064b4" - integrity sha512-MtMeFVlD2LIKjp2sE2xM2slq3Zxf9zwVuw0jemsxvh1QOpHSsSzfNOTH9uYW9i1MXFxUSMmLpeVeUzoNOKBaWg== +"@rollup/rollup-linux-ppc64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz#9f32074819eeb1ddbe51f50ea9dcd61a6745ec33" + integrity sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw== -"@rollup/rollup-linux-riscv64-gnu@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.56.0.tgz#ff6d51976e0830732880770a9e18553136b8d92b" - integrity sha512-in+v6wiHdzzVhYKXIk5U74dEZHdKN9KH0Q4ANHOTvyXPG41bajYRsy7a8TPKbYPl34hU7PP7hMVHRvv/5aCSew== +"@rollup/rollup-linux-riscv64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz#3fdb9d4b1e29fb6b6a6da9f15654d42eb77b99b2" + integrity sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A== -"@rollup/rollup-linux-riscv64-musl@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.56.0.tgz#325fb35eefc7e81d75478318f0deee1e4a111493" - integrity sha512-yni2raKHB8m9NQpI9fPVwN754mn6dHQSbDTwxdr9SE0ks38DTjLMMBjrwvB5+mXrX+C0npX0CVeCUcvvvD8CNQ== +"@rollup/rollup-linux-riscv64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz#1de780d64e6be0e3e8762035c22e0d8ea68df8ed" + integrity sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw== -"@rollup/rollup-linux-s390x-gnu@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.56.0.tgz#37410fabb5d3ba4ad34abcfbe9ba9b6288413f30" - integrity sha512-zhLLJx9nQPu7wezbxt2ut+CI4YlXi68ndEve16tPc/iwoylWS9B3FxpLS2PkmfYgDQtosah07Mj9E0khc3Y+vQ== +"@rollup/rollup-linux-s390x-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz#1da022ffd2d9e9f0fd8344ea49e113001fbcac64" + integrity sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg== -"@rollup/rollup-linux-x64-gnu@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.56.0.tgz#8ef907a53b2042068fc03fcc6a641e2b02276eca" - integrity sha512-MVC6UDp16ZSH7x4rtuJPAEoE1RwS8N4oK9DLHy3FTEdFoUTCFVzMfJl/BVJ330C+hx8FfprA5Wqx4FhZXkj2Kw== +"@rollup/rollup-linux-x64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz#78c16eef9520bd10e1ea7a112593bb58e2842622" + integrity sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg== -"@rollup/rollup-linux-x64-musl@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.56.0.tgz#61b9ba09ea219e0174b3f35a6ad2afc94bdd5662" - integrity sha512-ZhGH1eA4Qv0lxaV00azCIS1ChedK0V32952Md3FtnxSqZTBTd6tgil4nZT5cU8B+SIw3PFYkvyR4FKo2oyZIHA== +"@rollup/rollup-linux-x64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz#a7598591b4d9af96cb3167b50a5bf1e02dfea06c" + integrity sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw== -"@rollup/rollup-openbsd-x64@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.56.0.tgz#fc4e54133134c1787d0b016ffdd5aeb22a5effd3" - integrity sha512-O16XcmyDeFI9879pEcmtWvD/2nyxR9mF7Gs44lf1vGGx8Vg2DRNx11aVXBEqOQhWb92WN4z7fW/q4+2NYzCbBA== +"@rollup/rollup-openbsd-x64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz#c51d48c07cd6c466560e5bed934aec688ce02614" + integrity sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw== -"@rollup/rollup-openharmony-arm64@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.56.0.tgz#959ae225b1eeea0cc5b7c9f88e4834330fb6cd09" - integrity sha512-LhN/Reh+7F3RCgQIRbgw8ZMwUwyqJM+8pXNT6IIJAqm2IdKkzpCh/V9EdgOMBKuebIrzswqy4ATlrDgiOwbRcQ== +"@rollup/rollup-openharmony-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz#f09921d0b2a0b60afbf3586d2a7a7f208ba6df17" + integrity sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ== -"@rollup/rollup-win32-arm64-msvc@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.56.0.tgz#842acd38869fa1cbdbc240c76c67a86f93444c27" - integrity sha512-kbFsOObXp3LBULg1d3JIUQMa9Kv4UitDmpS+k0tinPBz3watcUiV2/LUDMMucA6pZO3WGE27P7DsfaN54l9ing== +"@rollup/rollup-win32-arm64-msvc@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz#08d491717135376e4a99529821c94ecd433d5b36" + integrity sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ== -"@rollup/rollup-win32-ia32-msvc@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.56.0.tgz#7ab654def4042df44cb29f8ed9d5044e850c66d5" - integrity sha512-vSSgny54D6P4vf2izbtFm/TcWYedw7f8eBrOiGGecyHyQB9q4Kqentjaj8hToe+995nob/Wv48pDqL5a62EWtg== +"@rollup/rollup-win32-ia32-msvc@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz#b0c12aac1104a8b8f26a5e0098e5facbb3e3964a" + integrity sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew== -"@rollup/rollup-win32-x64-gnu@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.56.0.tgz#7426cdec1b01d2382ffd5cda83cbdd1c8efb3ca6" - integrity sha512-FeCnkPCTHQJFbiGG49KjV5YGW/8b9rrXAM2Mz2kiIoktq2qsJxRD5giEMEOD2lPdgs72upzefaUvS+nc8E3UzQ== +"@rollup/rollup-win32-x64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz#b9cccef26f5e6fdc013bf3c0911a3c77428509d0" + integrity sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ== -"@rollup/rollup-win32-x64-msvc@4.56.0": - version "4.56.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.56.0.tgz#9eec0212732a432c71bde0350bc40b673d15b2db" - integrity sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g== +"@rollup/rollup-win32-x64-msvc@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz#a03348e7b559c792b6277cc58874b89ef46e1e72" + integrity sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA== "@socket.io/component-emitter@~3.1.0": version "3.1.2" @@ -1605,201 +1605,204 @@ dependencies: "@tanstack/virtual-core" "3.13.18" -"@tiptap/core@^2.26.1", "@tiptap/core@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.27.2.tgz#679eef9ce673d7243ce28d303852a98cbd1844be" - integrity sha512-ABL1N6eoxzDzC1bYvkMbvyexHacszsKdVPYqhl5GwHLOvpZcv9VE9QaKwDILTyz5voCA0lGcAAXZp+qnXOk5lQ== +"@tiptap/core@^3.11.0", "@tiptap/core@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-3.19.0.tgz#dca483b50e1b8a596f695aecde387a79fe7da717" + integrity sha512-bpqELwPW+DG8gWiD8iiFtSl4vIBooG5uVJod92Qxn3rA9nFatyXRr4kNbMJmOZ66ezUvmCjXVe/5/G4i5cyzKA== -"@tiptap/extension-blockquote@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.27.2.tgz#af5fccec360cd94b9d3d8751c868d92e9e70907d" - integrity sha512-oIGZgiAeA4tG3YxbTDfrmENL4/CIwGuP3THtHsNhwRqwsl9SfMk58Ucopi2GXTQSdYXpRJ0ahE6nPqB5D6j/Zw== +"@tiptap/extension-blockquote@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-3.19.0.tgz#86c52e8e3b6d1e072ae0d9c895723034a1e37096" + integrity sha512-y3UfqY9KD5XwWz3ndiiJ089Ij2QKeiXy/g1/tlAN/F1AaWsnkHEHMLxCP1BIqmMpwsX7rZjMLN7G5Lp7c9682A== -"@tiptap/extension-bold@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.27.2.tgz#612104c1e9eaba4c9301b21daa7ef19a9e487051" - integrity sha512-bR7J5IwjCGQ0s3CIxyMvOCnMFMzIvsc5OVZKscTN5UkXzFsaY6muUAIqtKxayBUucjtUskm5qZowJITCeCb1/A== +"@tiptap/extension-bold@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-3.19.0.tgz#ef0ddfd9b242ef9c25e3348aef9bf2dc681cdc19" + integrity sha512-UZgb1d0XK4J/JRIZ7jW+s4S6KjuEDT2z1PPM6ugcgofgJkWQvRZelCPbmtSFd3kwsD+zr9UPVgTh9YIuGQ8t+Q== -"@tiptap/extension-bubble-menu@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.27.2.tgz#f75eb12a8d2496bcde739b5c20684db635a48b9e" - integrity sha512-VkwlCOcr0abTBGzjPXklJ92FCowG7InU8+Od9FyApdLNmn0utRYGRhw0Zno6VgE9EYr1JY4BRnuSa5f9wlR72w== +"@tiptap/extension-bubble-menu@^3.11.0", "@tiptap/extension-bubble-menu@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.19.0.tgz#8e662fcf94c7365a8957a33e4e862aebf6761753" + integrity sha512-klNVIYGCdznhFkrRokzGd6cwzoi8J7E5KbuOfZBwFwhMKZhlz/gJfKmYg9TJopeUhrr2Z9yHgWTk8dh/YIJCdQ== dependencies: - tippy.js "^6.3.7" + "@floating-ui/dom" "^1.0.0" -"@tiptap/extension-bullet-list@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.27.2.tgz#2347683ab898471ab7df2c3e63b20e8d3d7c46f3" - integrity sha512-gmFuKi97u5f8uFc/GQs+zmezjiulZmFiDYTh3trVoLRoc2SAHOjGEB7qxdx7dsqmMN7gwiAWAEVurLKIi1lnnw== +"@tiptap/extension-bullet-list@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-3.19.0.tgz#acf12e952b6a5873dc20b58530f2f524807bbd6f" + integrity sha512-F9uNnqd0xkJbMmRxVI5RuVxwB9JaCH/xtRqOUNQZnRBt7IdAElCY+Dvb4hMCtiNv+enGM/RFGJuFHR9TxmI7rw== -"@tiptap/extension-code-block-lowlight@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.27.2.tgz#b2085bd884e0089414042896efac98e2dcb9a938" - integrity sha512-v6NKStBbQ/XCc1NnCi3ObsL1DsxadSIBtUQNA/B+urkPgn5LEy72HAGlf0xwjRaNkAGSaTASLKmc84L5q5zlGQ== +"@tiptap/extension-code-block-lowlight@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-3.19.0.tgz#9b2427250195c42e85aad09d37e4bf6345586af1" + integrity sha512-P8O8i1J+XozEVA7bF/Ijwf/r1rVqrh1DBQ7dXxBcrUvLpIGyVjtxX228jBF/kD4kf2xOlphvjDhV2fLa8XOVsg== -"@tiptap/extension-code-block@^2.26.1", "@tiptap/extension-code-block@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.27.2.tgz#0a622d5bf92c9db55e9f5eaba1a6a8d7a015b1f1" - integrity sha512-KgvdQHS4jXr79aU3wZOGBIZYYl9vCB7uDEuRFV4so2rYrfmiYMw3T8bTnlNEEGe4RUeAms1i4fdwwvQp9nR1Dw== +"@tiptap/extension-code-block@^3.11.0", "@tiptap/extension-code-block@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-3.19.0.tgz#71a7a362b3fa68c1789c8b9ac224ca89eb410630" + integrity sha512-b/2qR+tMn8MQb+eaFYgVk4qXnLNkkRYmwELQ8LEtEDQPxa5Vl7J3eu8+4OyoIFhZrNDZvvoEp80kHMCP8sI6rg== -"@tiptap/extension-code@^2.26.1", "@tiptap/extension-code@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.27.2.tgz#bfbaf07f67232144c6865ffbea20896e02c6fe6f" - integrity sha512-7X9AgwqiIGXoZX7uvdHQsGsjILnN/JaEVtqfXZnPECzKGaWHeK/Ao4sYvIIIffsyZJA8k5DC7ny2/0sAgr2TuA== +"@tiptap/extension-code@^3.11.0", "@tiptap/extension-code@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-3.19.0.tgz#15d53c139ad64d1debcc08c7ca5afbcc8e531f0b" + integrity sha512-2kqqQIXBXj2Or+4qeY3WoE7msK+XaHKL6EKOcKlOP2BW8eYqNTPzNSL+PfBDQ3snA7ljZQkTs/j4GYDj90vR1A== -"@tiptap/extension-color@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.27.2.tgz#2716ff99b7ece8ad095283bb62c794df9eabb5dc" - integrity sha512-sOKCP8/2V3sRM3FdWgMe1lFE5ewsWNCRafiVoujS1+TTHGCj4jw6W+LiumBUk7cRI8kXW/rqGWVC4RVdknYUCA== +"@tiptap/extension-color@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-3.19.0.tgz#663978ecf05fd0390463fb3f162c3fd35f9cf8b6" + integrity sha512-SemOrEEnmbKshhbTeKIvffwMlgqDAUDuOYyizfKqYM2dd5fRjohp+oszExO7scVhDtHtvtP/l3UmkBGBYfl4Tg== -"@tiptap/extension-document@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.27.2.tgz#697ee04c03c7b37bc37d942d60fcc5fa304988b5" - integrity sha512-CFhAYsPnyYnosDC4639sCJnBUnYH4Cat9qH5NZWHVvdgtDwu8GZgZn2eSzaKSYXWH1vJ9DSlCK+7UyC3SNXIBA== +"@tiptap/extension-document@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-3.19.0.tgz#dfa6889cff748d489e0bc1028918bf4571372ba5" + integrity sha512-AOf0kHKSFO0ymjVgYSYDncRXTITdTcrj1tqxVazrmO60KNl1Rc2dAggDvIVTEBy5NvceF0scc7q3sE/5ZtVV7A== -"@tiptap/extension-dropcursor@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.27.2.tgz#c0f62e32a6c7bc7dc8cc6b6edd84d9173bc1db16" - integrity sha512-oEu/OrktNoQXq1x29NnH/GOIzQZm8ieTQl3FK27nxfBPA89cNoH4mFEUmBL5/OFIENIjiYG3qWpg6voIqzswNw== +"@tiptap/extension-dropcursor@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-3.19.0.tgz#fbef441944842f23fe0a35154b519103166a4848" + integrity sha512-sf3dEZXiLvsGqVK2maUIzXY6qtYYCvBumag7+VPTMGQ0D4hiZ1X/4ukt4+6VXDg5R2WP1CoIt/QvUetUjWNhbQ== -"@tiptap/extension-floating-menu@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.27.2.tgz#b04e8f542d3900db1d845a03a0f5ab079a06daaf" - integrity sha512-GUN6gPIGXS7ngRJOwdSmtBRBDt9Kt9CM/9pSwKebhLJ+honFoNA+Y6IpVyDvvDMdVNgBchiJLs6qA5H97gAePQ== - dependencies: - tippy.js "^6.3.7" +"@tiptap/extension-floating-menu@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-3.19.0.tgz#9efa0bb3618fc49792789dc5f01c79493e6f2b56" + integrity sha512-JaoEkVRkt+Slq3tySlIsxnMnCjS0L5n1CA1hctjLy0iah8edetj3XD5mVv5iKqDzE+LIjF4nwLRRVKJPc8hFBg== -"@tiptap/extension-gapcursor@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.27.2.tgz#2e82dd87cb2dfcca90f0abb3b43f1f6748a54e2c" - integrity sha512-/c9VF1HBxj+AP54XGVgCmD9bEGYc5w5OofYCFQgM7l7PB1J00A4vOke0oPkHJnqnOOyPlFaxO/7N6l3XwFcnKA== +"@tiptap/extension-gapcursor@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-3.19.0.tgz#64e5462a4ab2f0bd110738410dcbf3597d76349f" + integrity sha512-w7DACS4oSZaDWjz7gropZHPc9oXqC9yERZTcjWxyORuuIh1JFf0TRYspleK+OK28plK/IftojD/yUDn1MTRhvA== -"@tiptap/extension-hard-break@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.27.2.tgz#250200feb316cfb40ed8e9188ee6684c2811b475" - integrity sha512-kSRVGKlCYK6AGR0h8xRkk0WOFGXHIIndod3GKgWU49APuIGDiXd8sziXsSlniUsWmqgDmDXcNnSzPcV7AQ8YNg== +"@tiptap/extension-hard-break@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-3.19.0.tgz#7120524cec9ed4b957963693cb4c57cbecbaecf8" + integrity sha512-lAmQraYhPS5hafvCl74xDB5+bLuNwBKIEsVoim35I0sDJj5nTrfhaZgMJ91VamMvT+6FF5f1dvBlxBxAWa8jew== -"@tiptap/extension-heading@^2.26.1", "@tiptap/extension-heading@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.27.2.tgz#10afd812475c6a3f62a26bd1975998bfa94cb9fb" - integrity sha512-iM3yeRWuuQR/IRQ1djwNooJGfn9Jts9zF43qZIUf+U2NY8IlvdNsk2wTOdBgh6E0CamrStPxYGuln3ZS4fuglw== +"@tiptap/extension-heading@^3.11.0", "@tiptap/extension-heading@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-3.19.0.tgz#d0bc93426c01a2ed36b9124c1a8205ab3945e77a" + integrity sha512-uLpLlfyp086WYNOc0ekm1gIZNlEDfmzOhKzB0Hbyi6jDagTS+p9mxUNYeYOn9jPUxpFov43+Wm/4E24oY6B+TQ== -"@tiptap/extension-highlight@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.27.2.tgz#5647a82ac2e1c04532e0d8dbc15946f58d6151ae" - integrity sha512-ZjlktDdMjruMJFAVz0TbQf0v92Jqkc7Ri1iZJqBXuLid+r+GxUzl2CVAV7qq5yagkGQgvAG+WGsMk880HgR3MA== +"@tiptap/extension-highlight@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-3.19.0.tgz#8e51114c85d93b2bb0437642c4da92e5b69fac01" + integrity sha512-MYwSDCh/aG12KXw30XmHwrruElBRB8b7Ou0jd8n8H2oXb+QexVqnMa2+ylkuTAl+2D5PR7zdIIOeeHRSTmkPPw== -"@tiptap/extension-history@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.27.2.tgz#43c6d976c521dc1cf2d4a0707df7d8328be0e9a9" - integrity sha512-+hSyqERoFNTWPiZx4/FCyZ/0eFqB9fuMdTB4AC/q9iwu3RNWAQtlsJg5230bf/qmyO6bZxRUc0k8p4hrV6ybAw== +"@tiptap/extension-horizontal-rule@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.19.0.tgz#0e77078fcd53beca786277ce83d259e2103cc361" + integrity sha512-iqUHmgMGhMgYGwG6L/4JdelVQ5Mstb4qHcgTGd/4dkcUOepILvhdxajPle7OEdf9sRgjQO6uoAU5BVZVC26+ng== -"@tiptap/extension-horizontal-rule@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.27.2.tgz#7440adb913dfe270577d1853cfc2f725f36e0040" - integrity sha512-WGWUSgX+jCsbtf9Y9OCUUgRZYuwjVoieW5n6mAUohJ9/6gc6sGIOrUpBShf+HHo6WD+gtQjRd+PssmX3NPWMpg== +"@tiptap/extension-image@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-3.19.0.tgz#995d49e229a4c3d5511ec506b616b084cd972c64" + integrity sha512-/rGl8nBziBPVJJ/9639eQWFDKcI3RQsDM3s+cqYQMFQfMqc7sQB9h4o4sHCBpmKxk3Y0FV/0NjnjLbBVm8OKdQ== -"@tiptap/extension-image@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.27.2.tgz#c962eaae3d390e1641cffacdbd61af613306c32c" - integrity sha512-5zL/BY41FIt72azVrCrv3n+2YJ/JyO8wxCcA4Dk1eXIobcgVyIdo4rG39gCqIOiqziAsqnqoj12QHTBtHsJ6mQ== +"@tiptap/extension-italic@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-3.19.0.tgz#af2a9c095ec846e379041f3e17e1dd101a5a4bf8" + integrity sha512-6GffxOnS/tWyCbDkirWNZITiXRta9wrCmrfa4rh+v32wfaOL1RRQNyqo9qN6Wjyl1R42Js+yXTzTTzZsOaLMYA== -"@tiptap/extension-italic@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.27.2.tgz#91b6ded7b84ed218a8c07ed979332d0dbf923d2b" - integrity sha512-1OFsw2SZqfaqx5Fa5v90iNlPRcqyt+lVSjBwTDzuPxTPFY4Q0mL89mKgkq2gVHYNCiaRkXvFLDxaSvBWbmthgg== - -"@tiptap/extension-link@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.27.2.tgz#f250b6119b02f836e0746af4c28766b643b78f6c" - integrity sha512-bnP61qkr0Kj9Cgnop1hxn2zbOCBzNtmawxr92bVTOE31fJv6FhtCnQiD6tuPQVGMYhcmAj7eihtvuEMFfqEPcQ== +"@tiptap/extension-link@^3.11.0", "@tiptap/extension-link@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-3.19.0.tgz#e8e656735bda6ca1d4b6577821e06274ab0ff6c8" + integrity sha512-HEGDJnnCPfr7KWu7Dsq+eRRe/mBCsv6DuI+7fhOCLDJjjKzNgrX2abbo/zG3D/4lCVFaVb+qawgJubgqXR/Smw== dependencies: linkifyjs "^4.3.2" -"@tiptap/extension-list-item@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.27.2.tgz#562a8a5f56ed7ac70cd4fab37d7fbcd29e9dc078" - integrity sha512-eJNee7IEGXMnmygM5SdMGDC8m/lMWmwNGf9fPCK6xk0NxuQRgmZHL6uApKcdH6gyNcRPHCqvTTkhEP7pbny/fg== +"@tiptap/extension-list-item@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-3.19.0.tgz#b2218ff6be694b581fd7d817810a33ee1c218311" + integrity sha512-VsSKuJz4/Tb6ZmFkXqWpDYkRzmaLTyE6dNSEpNmUpmZ32sMqo58mt11/huADNwfBFB0Ve7siH/VnFNIJYY3xvg== -"@tiptap/extension-mention@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-mention/-/extension-mention-2.27.2.tgz#13d66c56fa57dc7c28f561459d2ffb3936ad2fe3" - integrity sha512-uHxVf8RISscb4xgCEJmDSNcFQmzlBTKJh7fp2QAXWIF4Xtrg3zD08PIXUvvHapoluGD9OdBugW4YCu1PJ3xWNw== +"@tiptap/extension-list-keymap@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-keymap/-/extension-list-keymap-3.19.0.tgz#41b87b154560aad92e779bff5c6e32e125b792ea" + integrity sha512-bxgmAgA3RzBGA0GyTwS2CC1c+QjkJJq9hC+S6PSOWELGRiTbwDN3MANksFXLjntkTa0N5fOnL27vBHtMStURqw== -"@tiptap/extension-ordered-list@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.27.2.tgz#12f2c4309512429a0c21863e741db00356573a4b" - integrity sha512-M7A4tLGJcLPYdLC4CI2Gwl8LOrENQW59u3cMVa+KkwG1hzSJyPsbDpa1DI6oXPC2WtYiTf22zrbq3gVvH+KA2w== +"@tiptap/extension-list@^3.11.0", "@tiptap/extension-list@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list/-/extension-list-3.19.0.tgz#737dcb56ba9838a4431c1afb035bd622fab46d21" + integrity sha512-N6nKbFB2VwMsPlCw67RlAtYSK48TAsAUgjnD+vd3ieSlIufdQnLXDFUP6hFKx9mwoUVUgZGz02RA6bkxOdYyTw== -"@tiptap/extension-paragraph@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.27.2.tgz#e6873c16993bf21b831ecac41bbd137dc5945eb4" - integrity sha512-elYVn2wHJJ+zB9LESENWOAfI4TNT0jqEN34sMA/hCtA4im1ZG2DdLHwkHIshj/c4H0dzQhmsS/YmNC5Vbqab/A== +"@tiptap/extension-mention@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-mention/-/extension-mention-3.19.0.tgz#676fede8ec7b84512b19478660ef3fcb60bd1578" + integrity sha512-iBWX6mUouvDe9F75C2fJnFzvBFYVF8fcOa7UvzqWHRSCt8WxqSIp6C1B9Y0npP4TbIZySHzPV4NQQJhtmWwKww== -"@tiptap/extension-placeholder@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.27.2.tgz#5ac421cbc0bb2bf5909e3dcc9a61fec19cab0c53" - integrity sha512-IjsgSVYJRjpAKmIoapU0E2R4E2FPY3kpvU7/1i7PUYisylqejSJxmtJPGYw0FOMQY9oxnEEvfZHMBA610tqKpg== +"@tiptap/extension-node-range@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-node-range/-/extension-node-range-3.19.0.tgz#182a5fc0b42d6a3230d61a1a1330d88e8acb569c" + integrity sha512-rIq1e+jTzdtHrGyWKZgRUJc8Phz5Crh1WqBL71QPJgLZqGbcCeGTHBFBOrU2AWwQNa8lYEbGD+FTFxVfvxegUA== -"@tiptap/extension-strike@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.27.2.tgz#9291f6dd9bcf00e1c2b7e043f9d9b18cf35f1db1" - integrity sha512-HHIjhafLhS2lHgfAsCwC1okqMsQzR4/mkGDm4M583Yftyjri1TNA7lzhzXWRFWiiMfJxKtdjHjUAQaHuteRTZw== +"@tiptap/extension-ordered-list@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-3.19.0.tgz#f6f8bfe41d3429c505b44764b473b6dfd7bcd2a1" + integrity sha512-cxGsINquwHYE1kmhAcLNLHAofmoDEG6jbesR5ybl7tU5JwtKVO7S/xZatll2DU1dsDAXWPWEeeMl4e/9svYjCg== -"@tiptap/extension-table-cell@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.27.2.tgz#ff7a7b854bd7536e81345813cef1c3f38f2eff55" - integrity sha512-9Lk46MjZMFzVZfOj9Kd7VgC6Odt6vmEhlCYVumErShUY7EkFqCw3b2IYoUtQkntfOEx/Afnhff/okNQwPsJeUA== +"@tiptap/extension-paragraph@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-3.19.0.tgz#91adde189aabf13a2bfbb2d961833d3bc2bc055f" + integrity sha512-xWa6gj82l5+AzdYyrSk9P4ynySaDzg/SlR1FarXE5yPXibYzpS95IWaVR0m2Qaz7Rrk+IiYOTGxGRxcHLOelNg== -"@tiptap/extension-table-header@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.27.2.tgz#9b006bb4cc0a1b8e6038803e9ab2533273535a19" - integrity sha512-ZEb6lbG0NbbodWLV0b4BS/QrDIPlUbCcuOsUxzqVvlMUY1Vg6Fj6fKwLaBcsIUDHi8sxZDBEgYEDw3BR/zcO6A== +"@tiptap/extension-placeholder@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-3.19.0.tgz#648f8d65b389b9bc2902d5aa38a0218446579f6d" + integrity sha512-i15OfgyI4IDCYAcYSKUMnuZkYuUInfanjf9zquH8J2BETiomf/jZldVCp/QycMJ8DOXZ38fXDc99wOygnSNySg== -"@tiptap/extension-table-row@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.27.2.tgz#8fe2a648fb005e9cbf9da2bc08e3c04becd260ce" - integrity sha512-Nw9+tA56Y5HtLVP01NGCZSUuTQhJPtfK9OfmDgGgcxynn2cRVdEtj+9FNZqRhQ1iRVaAI+Rd4xRvX9qYePMOxw== +"@tiptap/extension-strike@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-3.19.0.tgz#eac7712cc791488f4c1c48baf3aed1a8d95f398c" + integrity sha512-xYpabHsv7PccLUBQaP8AYiFCnYbx6P93RHPd0lgNwhdOjYFd931Zy38RyoxPHAgbYVmhf1iyx7lpuLtBnhS5dA== -"@tiptap/extension-table@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.27.2.tgz#0f738d5205579a770323d19da5c5b49a1f61a169" - integrity sha512-pDbhOpT5phZkcsyPjGBQlXv0+0hmdrvqHJ+dJjkGcCtlfy2pHiEIhmIItOFagc7wXy8G9iUFZ9Jie4zvDf+brg== +"@tiptap/extension-table@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-3.19.0.tgz#a5f9be88e319f60dc7b8df1321f95a31b20fe991" + integrity sha512-Lg8DlkkDUMYE/CcGOxoCWF98B2i7VWh+AGgqlF+XWrHjhlKHfENLRXm1a0vWuyyP3NknRYILoaaZ1s7QzmXKRA== -"@tiptap/extension-task-item@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.27.2.tgz#9df3056ffadd2b9f1de68048383e3841a1747417" - integrity sha512-ZBSqj/dygB/Rp5K9qOxRVwASTZCmKVoTq8C59KvMgD/aFjJxhq/w2dZaWkCUEXEep+NmvJqo0kfeAEMY5UDnGg== +"@tiptap/extension-task-item@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-3.19.0.tgz#65b43213b349b5f5f8010371c7a7a0e0b4f6629d" + integrity sha512-1il70SoaoEA5jKr2QS30CpZoB7EzdSLugROMBPRUPc0feIBKAf6yUPhxlFyU4ez/uT4Pazsf1HAgHI3AOr+MtQ== -"@tiptap/extension-task-list@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.27.2.tgz#8607e41d8d371278a82edda3b804512adfdaae6e" - integrity sha512-5nupAewdzZ9F3599oAcaK0WkDH04wdACAVBPM4zG7InlIpkbho3txB7zWmm64OxfhCMIMGKiXY1q0bw9i0QBGQ== +"@tiptap/extension-task-list@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-3.19.0.tgz#d52738589fc67fc7db849d23b035c0d6525bac99" + integrity sha512-Slb6YZi7XpVT966oAJhqzZu4LVuHtUeZgMxA0bdc8FSZBxntcr8OQWmPbqvR437RAR/Xd7b5quXS3JmSeksyvA== -"@tiptap/extension-text-align@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text-align/-/extension-text-align-2.27.2.tgz#ce29f871526d32502bd9f3292b84a57d76d66e60" - integrity sha512-0Pyks6Hu+Q/+9+5/osoSv0SP6jIerdWMYbi13aaZLsJoj3lBj5WNaE11JtAwSFN5sx0IbqhDSlp1zkvRnzgZ8g== +"@tiptap/extension-text-align@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text-align/-/extension-text-align-3.19.0.tgz#184c2fe82a04ae23c59ee688d9d64bc465c5da63" + integrity sha512-cY8bHWYojLTHXZb2j2srdh7ltmDgnwXYvSxbPL4HK4j7XxQOGnOsTakgM/BNhxymOfEj2414i5Otyy8hlgviFA== -"@tiptap/extension-text-style@^2.26.1", "@tiptap/extension-text-style@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.27.2.tgz#5f27d512e8421b5160be37aab17c47dde88a8bea" - integrity sha512-Omk+uxjJLyEY69KStpCw5fA9asvV+MGcAX2HOxyISDFoLaL49TMrNjhGAuz09P1L1b0KGXo4ml7Q3v/Lfy4WPA== +"@tiptap/extension-text-style@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-3.19.0.tgz#c22250347778f67c42a5f12a6dcdee067001d756" + integrity sha512-R55V6iUfRq03SGt/R2KvaeN+XGFiKJHx1jFJhZzvnWhMV7YqjHSG2r4BLvpTq1HBqteMbEjI+EOnb4t9AKd6aQ== -"@tiptap/extension-text@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.27.2.tgz#8b387a95cef4adb112bfb1ed00a8bc50d9204476" - integrity sha512-Xk7nYcigljAY0GO9hAQpZ65ZCxqOqaAlTPDFcKerXmlkQZP/8ndx95OgUb1Xf63kmPOh3xypurGS2is3v0MXSA== +"@tiptap/extension-text@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-3.19.0.tgz#353278c97bd8f5bdc29f06942fbd1e856bdb5b18" + integrity sha512-K95+SnbZy0h6hNFtfy23n8t/nOcTFEf69In9TSFVVmwn/Nwlke+IfiESAkqbt1/7sKJeegRXYO7WzFEmFl9Q/g== -"@tiptap/extension-typography@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/extension-typography/-/extension-typography-2.27.2.tgz#1cbff5833ed8335da47b1b13e7193bcc82248ab8" - integrity sha512-NSyqDa8PlAZoVRfTWQuxueTZ6ftOD72EV7UKVpftf3C+Heme727mvwl1YHMnagOlqVoxBhFOrl9CnSs/q5uayQ== +"@tiptap/extension-typography@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-typography/-/extension-typography-3.19.0.tgz#8b9efe36524bdbe564bdda1dd793b97867f58008" + integrity sha512-2Rwwz1ErNhqUcXPzPX2u4frdyrK4Yj6ZMvCLPxLt5lQXj9Eq9YEoD9isw8abR105ko3BCidvfElQYSFu6dWPSw== -"@tiptap/pm@^2.26.1", "@tiptap/pm@^2.27.2": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.27.2.tgz#2e8b187df66eea54702cfba9820800c8d10c21ef" - integrity sha512-kaEg7BfiJPDQMKbjVIzEPO3wlcA+pZb2tlcK9gPrdDnEFaec2QTF1sXz2ak2IIb2curvnIrQ4yrfHgLlVA72wA== +"@tiptap/extension-underline@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-3.19.0.tgz#bbc81d085725981d256127ab416f91d0802ec2a4" + integrity sha512-800MGEWfG49j10wQzAFiW/ele1HT04MamcL8iyuPNu7ZbjbGN2yknvdrJlRy7hZlzIrVkZMr/1tz62KN33VHIw== + +"@tiptap/extensions@^3.11.0", "@tiptap/extensions@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extensions/-/extensions-3.19.0.tgz#5747c0ebf460b9669e8b4362561872448f66abfe" + integrity sha512-ZmGUhLbMWaGqnJh2Bry+6V4M6gMpUDYo4D1xNux5Gng/E/eYtc+PMxMZ/6F7tNTAuujLBOQKj6D+4SsSm457jw== + +"@tiptap/pm@^3.11.0", "@tiptap/pm@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-3.19.0.tgz#5cb499c7b2603ec6550d0c7a70b924f27fdb7692" + integrity sha512-789zcnM4a8OWzvbD2DL31d0wbSm9BVeO/R7PLQwLIGysDI3qzrcclyZ8yhqOEVuvPitRRwYLq+mY14jz7kY4cw== dependencies: prosemirror-changeset "^2.3.0" prosemirror-collab "^1.3.1" @@ -1811,54 +1814,57 @@ prosemirror-keymap "^1.2.2" prosemirror-markdown "^1.13.1" prosemirror-menu "^1.2.4" - prosemirror-model "^1.23.0" + prosemirror-model "^1.24.1" prosemirror-schema-basic "^1.2.3" - prosemirror-schema-list "^1.4.1" + prosemirror-schema-list "^1.5.0" prosemirror-state "^1.4.3" prosemirror-tables "^1.6.4" prosemirror-trailing-node "^3.0.0" prosemirror-transform "^1.10.2" - prosemirror-view "^1.37.0" + prosemirror-view "^1.38.1" -"@tiptap/starter-kit@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.27.2.tgz#8cad96757376109ce9028c0dc2e941778e5051e9" - integrity sha512-bb0gJvPoDuyRUQ/iuN52j1//EtWWttw+RXAv1uJxfR0uKf8X7uAqzaOOgwjknoCIDC97+1YHwpGdnRjpDkOBxw== +"@tiptap/starter-kit@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-3.19.0.tgz#312440bd18c3cce379ea8eab3fe174b8141dd313" + integrity sha512-dTCkHEz+Y8ADxX7h+xvl6caAj+3nII/wMB1rTQchSuNKqJTOrzyUsCWm094+IoZmLT738wANE0fRIgziNHs/ug== dependencies: - "@tiptap/core" "^2.27.2" - "@tiptap/extension-blockquote" "^2.27.2" - "@tiptap/extension-bold" "^2.27.2" - "@tiptap/extension-bullet-list" "^2.27.2" - "@tiptap/extension-code" "^2.27.2" - "@tiptap/extension-code-block" "^2.27.2" - "@tiptap/extension-document" "^2.27.2" - "@tiptap/extension-dropcursor" "^2.27.2" - "@tiptap/extension-gapcursor" "^2.27.2" - "@tiptap/extension-hard-break" "^2.27.2" - "@tiptap/extension-heading" "^2.27.2" - "@tiptap/extension-history" "^2.27.2" - "@tiptap/extension-horizontal-rule" "^2.27.2" - "@tiptap/extension-italic" "^2.27.2" - "@tiptap/extension-list-item" "^2.27.2" - "@tiptap/extension-ordered-list" "^2.27.2" - "@tiptap/extension-paragraph" "^2.27.2" - "@tiptap/extension-strike" "^2.27.2" - "@tiptap/extension-text" "^2.27.2" - "@tiptap/extension-text-style" "^2.27.2" - "@tiptap/pm" "^2.27.2" + "@tiptap/core" "^3.19.0" + "@tiptap/extension-blockquote" "^3.19.0" + "@tiptap/extension-bold" "^3.19.0" + "@tiptap/extension-bullet-list" "^3.19.0" + "@tiptap/extension-code" "^3.19.0" + "@tiptap/extension-code-block" "^3.19.0" + "@tiptap/extension-document" "^3.19.0" + "@tiptap/extension-dropcursor" "^3.19.0" + "@tiptap/extension-gapcursor" "^3.19.0" + "@tiptap/extension-hard-break" "^3.19.0" + "@tiptap/extension-heading" "^3.19.0" + "@tiptap/extension-horizontal-rule" "^3.19.0" + "@tiptap/extension-italic" "^3.19.0" + "@tiptap/extension-link" "^3.19.0" + "@tiptap/extension-list" "^3.19.0" + "@tiptap/extension-list-item" "^3.19.0" + "@tiptap/extension-list-keymap" "^3.19.0" + "@tiptap/extension-ordered-list" "^3.19.0" + "@tiptap/extension-paragraph" "^3.19.0" + "@tiptap/extension-strike" "^3.19.0" + "@tiptap/extension-text" "^3.19.0" + "@tiptap/extension-underline" "^3.19.0" + "@tiptap/extensions" "^3.19.0" + "@tiptap/pm" "^3.19.0" -"@tiptap/suggestion@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.27.2.tgz#901c1bbb5f12002cfe78a1ad40577727c23c374e" - integrity sha512-dQyvCIg0hcAVeh4fCIVCxogvbp+bF+GpbUb8sNlgnGrmHXnapGxzkvrlHnvneXZxLk/j7CxmBPKJNnm4Pbx4zw== +"@tiptap/suggestion@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-3.19.0.tgz#47ab6da8f70edd3bb98bf68e8d83b07ba5406981" + integrity sha512-tUZwMRFqTVPIo566ZmHNRteyZxJy2EE4FA+S3IeIUOOvY6AW0h1imhbpBO7sXV8CeEQvpa+2DWwLvy7L3vmstA== -"@tiptap/vue-3@^2.26.1": - version "2.27.2" - resolved "https://registry.yarnpkg.com/@tiptap/vue-3/-/vue-3-2.27.2.tgz#5a2dd974d3cee785c56a74bfc37cc813d3d86dde" - integrity sha512-NahnVLTAQsbLaNU9nGLdGCr88nAeQZJTejjBVQc3EzMdijmE46R44Rosj6O/pj3e7eLj1/gYvc+U/hIVbxMpoQ== - dependencies: - "@tiptap/extension-bubble-menu" "^2.27.2" - "@tiptap/extension-floating-menu" "^2.27.2" +"@tiptap/vue-3@^3.11.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/vue-3/-/vue-3-3.19.0.tgz#27b749520080cde9ff7b748b2674e901c63e7d77" + integrity sha512-H/w8k++Dv5ejacbPX6VEYqWpvcrAvU+iPggIU8XGZNOkCY9jKiHRXNXXEev/ScNhHm4E1itGJZFsgqJmtiCHLw== + optionalDependencies: + "@tiptap/extension-bubble-menu" "^3.19.0" + "@tiptap/extension-floating-menu" "^3.19.0" "@types/estree@0.0.39": version "0.0.39" @@ -1896,9 +1902,9 @@ integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg== "@types/node@*": - version "25.0.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-25.0.10.tgz#4864459c3c9459376b8b75fd051315071c8213e7" - integrity sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg== + version "25.2.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.2.3.tgz#9c18245be768bdb4ce631566c7da303a5c99a7f8" + integrity sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ== dependencies: undici-types "~7.16.0" @@ -1948,90 +1954,90 @@ resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-5.0.3.tgz#164b36653910d27c130cf6c945b4bd9bde5bcbee" integrity sha512-b8S5dVS40rgHdDrw+DQi/xOM9ed+kSRZzfm1T74bMmBDCd8XO87NKlFYInzCtwvtWwXZvo1QxE2OSspTATWrbA== -"@vue/compiler-core@3.5.27": - version "3.5.27" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.27.tgz#ce4402428e26095586eb889c41f6e172eb3960bd" - integrity sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ== +"@vue/compiler-core@3.5.28": + version "3.5.28" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.28.tgz#8298ab91d34b2c0d7d398384cd840471919e7e34" + integrity sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ== dependencies: - "@babel/parser" "^7.28.5" - "@vue/shared" "3.5.27" - entities "^7.0.0" + "@babel/parser" "^7.29.0" + "@vue/shared" "3.5.28" + entities "^7.0.1" estree-walker "^2.0.2" source-map-js "^1.2.1" -"@vue/compiler-dom@3.5.27": - version "3.5.27" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.27.tgz#32b2bc87f0a652c253986796ace0ed6213093af8" - integrity sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w== +"@vue/compiler-dom@3.5.28": + version "3.5.28" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.28.tgz#4e27b885898f4799d95305dfc56d14c2dcf8e5ba" + integrity sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA== dependencies: - "@vue/compiler-core" "3.5.27" - "@vue/shared" "3.5.27" + "@vue/compiler-core" "3.5.28" + "@vue/shared" "3.5.28" -"@vue/compiler-sfc@3.5.27": - version "3.5.27" - resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.27.tgz#84651b8816bf8e7d6e62fddd14db86efd6d6f1b6" - integrity sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ== +"@vue/compiler-sfc@3.5.28": + version "3.5.28" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.28.tgz#767aa5290da25a5b555d4c3cae53187159f915d6" + integrity sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g== dependencies: - "@babel/parser" "^7.28.5" - "@vue/compiler-core" "3.5.27" - "@vue/compiler-dom" "3.5.27" - "@vue/compiler-ssr" "3.5.27" - "@vue/shared" "3.5.27" + "@babel/parser" "^7.29.0" + "@vue/compiler-core" "3.5.28" + "@vue/compiler-dom" "3.5.28" + "@vue/compiler-ssr" "3.5.28" + "@vue/shared" "3.5.28" estree-walker "^2.0.2" magic-string "^0.30.21" postcss "^8.5.6" source-map-js "^1.2.1" -"@vue/compiler-ssr@3.5.27": - version "3.5.27" - resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.27.tgz#b480cad09dacf8f3d9c82b9843402f1a803baee7" - integrity sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw== +"@vue/compiler-ssr@3.5.28": + version "3.5.28" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.28.tgz#bfd3d39b3085b77220eaa278e5fbe3c93ffbc9c2" + integrity sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g== dependencies: - "@vue/compiler-dom" "3.5.27" - "@vue/shared" "3.5.27" + "@vue/compiler-dom" "3.5.28" + "@vue/shared" "3.5.28" "@vue/devtools-api@^6.5.0", "@vue/devtools-api@^6.6.4": version "6.6.4" resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz#cbe97fe0162b365edc1dba80e173f90492535343" integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g== -"@vue/reactivity@3.5.27": - version "3.5.27" - resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.27.tgz#d870557de1389a27b8abcb7cbfa30978dc69a000" - integrity sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ== +"@vue/reactivity@3.5.28": + version "3.5.28" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.28.tgz#8c6f8cf6bb3cfab94a1a7814eb6e2bf181ba8d51" + integrity sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw== dependencies: - "@vue/shared" "3.5.27" + "@vue/shared" "3.5.28" -"@vue/runtime-core@3.5.27": - version "3.5.27" - resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.27.tgz#bb43744ed070166c7d581b849ac22b71a9ccf127" - integrity sha512-fxVuX/fzgzeMPn/CLQecWeDIFNt3gQVhxM0rW02Tvp/YmZfXQgcTXlakq7IMutuZ/+Ogbn+K0oct9J3JZfyk3A== +"@vue/runtime-core@3.5.28": + version "3.5.28" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.28.tgz#f646861ac99d7b71a69c5b8e710923046ce01875" + integrity sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ== dependencies: - "@vue/reactivity" "3.5.27" - "@vue/shared" "3.5.27" + "@vue/reactivity" "3.5.28" + "@vue/shared" "3.5.28" -"@vue/runtime-dom@3.5.27": - version "3.5.27" - resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.27.tgz#392513252c7ca7e5277240fdc70b8093449127f5" - integrity sha512-/QnLslQgYqSJ5aUmb5F0z0caZPGHRB8LEAQ1s81vHFM5CBfnun63rxhvE/scVb/j3TbBuoZwkJyiLCkBluMpeg== +"@vue/runtime-dom@3.5.28": + version "3.5.28" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.28.tgz#86fba16e43ab48d959c8e8a6fb2caec5555d0fd7" + integrity sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA== dependencies: - "@vue/reactivity" "3.5.27" - "@vue/runtime-core" "3.5.27" - "@vue/shared" "3.5.27" + "@vue/reactivity" "3.5.28" + "@vue/runtime-core" "3.5.28" + "@vue/shared" "3.5.28" csstype "^3.2.3" -"@vue/server-renderer@3.5.27": - version "3.5.27" - resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.27.tgz#8137d0d7ec3b59d5992bb04c553775d209dddba7" - integrity sha512-qOz/5thjeP1vAFc4+BY3Nr6wxyLhpeQgAE/8dDtKo6a6xdk+L4W46HDZgNmLOBUDEkFXV3G7pRiUqxjX0/2zWA== +"@vue/server-renderer@3.5.28": + version "3.5.28" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.28.tgz#c59838d4d6fe89bec949db6ebf8625bd9264ad77" + integrity sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg== dependencies: - "@vue/compiler-ssr" "3.5.27" - "@vue/shared" "3.5.27" + "@vue/compiler-ssr" "3.5.28" + "@vue/shared" "3.5.28" -"@vue/shared@3.5.27": - version "3.5.27" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.27.tgz#33a63143d8fb9ca1b3efbc7ecf9bd0ab05f7e06e" - integrity sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ== +"@vue/shared@3.5.28": + version "3.5.28" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.28.tgz#ed9b6785e9452621ad3ab2f2775e9cba494a9ef4" + integrity sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ== "@vueuse/core@^10.11.0", "@vueuse/core@^10.4.1": version "10.11.1" @@ -2043,39 +2049,24 @@ "@vueuse/shared" "10.11.1" vue-demi ">=0.14.8" -"@vueuse/core@^12.5.0": - version "12.8.2" - resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-12.8.2.tgz#007c6dd29a7d1f6933e916e7a2f8ef3c3f968eaa" - integrity sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ== - dependencies: - "@types/web-bluetooth" "^0.0.21" - "@vueuse/metadata" "12.8.2" - "@vueuse/shared" "12.8.2" - vue "^3.5.13" - "@vueuse/core@^14.1.0": - version "14.1.0" - resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-14.1.0.tgz#274e98e591a505333b7dfb2bcaf7b4530a10b9c9" - integrity sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw== + version "14.2.1" + resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-14.2.1.tgz#b5cf36a07b4ea973381e18523ad0ed6ddc98a5be" + integrity sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ== dependencies: "@types/web-bluetooth" "^0.0.21" - "@vueuse/metadata" "14.1.0" - "@vueuse/shared" "14.1.0" + "@vueuse/metadata" "14.2.1" + "@vueuse/shared" "14.2.1" "@vueuse/metadata@10.11.1": version "10.11.1" resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-10.11.1.tgz#209db7bb5915aa172a87510b6de2ca01cadbd2a7" integrity sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw== -"@vueuse/metadata@12.8.2": - version "12.8.2" - resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-12.8.2.tgz#6cb3a4e97cdcf528329eebc1bda73cd7f64318d3" - integrity sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A== - -"@vueuse/metadata@14.1.0": - version "14.1.0" - resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-14.1.0.tgz#70fc2e94775e4a07369f11f86f6f0a465b04a381" - integrity sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA== +"@vueuse/metadata@14.2.1": + version "14.2.1" + resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-14.2.1.tgz#bd3338a565c2f651b9d18ac0f8825aa6077ee461" + integrity sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw== "@vueuse/shared@10.11.1", "@vueuse/shared@^10.11.0": version "10.11.1" @@ -2084,17 +2075,10 @@ dependencies: vue-demi ">=0.14.8" -"@vueuse/shared@12.8.2", "@vueuse/shared@^12.5.0": - version "12.8.2" - resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-12.8.2.tgz#b9e4611d0603629c8e151f982459da394e22f930" - integrity sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w== - dependencies: - vue "^3.5.13" - -"@vueuse/shared@14.1.0": - version "14.1.0" - resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-14.1.0.tgz#49b2face86a9c0c52e20eaf4c732a0223276c11f" - integrity sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw== +"@vueuse/shared@14.2.1", "@vueuse/shared@^14.1.0": + version "14.2.1" + resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-14.2.1.tgz#829a271147937f6b105bb1422d3171e6142f47ba" + integrity sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw== "@yr/monotone-cubic-spline@^1.0.3": version "1.0.3" @@ -2112,9 +2096,9 @@ acorn@^8.14.1, acorn@^8.15.0: integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== ajv@^8.6.0: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" - integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + version "8.18.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.18.0.tgz#8864186b6738d003eb3a933172bb3833e10cefbc" + integrity sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A== dependencies: fast-deep-equal "^3.1.3" fast-uri "^3.0.1" @@ -2230,29 +2214,29 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" -babel-plugin-polyfill-corejs2@^0.4.14: - version "0.4.14" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz#8101b82b769c568835611542488d463395c2ef8f" - integrity sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg== +babel-plugin-polyfill-corejs2@^0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz#808fa349686eea4741807cfaaa2aa3aa57ce120a" + integrity sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw== dependencies: - "@babel/compat-data" "^7.27.7" - "@babel/helper-define-polyfill-provider" "^0.6.5" + "@babel/compat-data" "^7.28.6" + "@babel/helper-define-polyfill-provider" "^0.6.6" semver "^6.3.1" -babel-plugin-polyfill-corejs3@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz#bb7f6aeef7addff17f7602a08a6d19a128c30164" - integrity sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A== +babel-plugin-polyfill-corejs3@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz#65b06cda48d6e447e1e926681f5a247c6ae2b9cf" + integrity sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ== dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.5" - core-js-compat "^3.43.0" + "@babel/helper-define-polyfill-provider" "^0.6.6" + core-js-compat "^3.48.0" -babel-plugin-polyfill-regenerator@^0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz#32752e38ab6f6767b92650347bf26a31b16ae8c5" - integrity sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg== +babel-plugin-polyfill-regenerator@^0.6.6: + version "0.6.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz#69f5dd263cab933c42fe5ea05e83443b374bd4bf" + integrity sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A== dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.5" + "@babel/helper-define-polyfill-provider" "^0.6.6" balanced-match@^1.0.0: version "1.0.2" @@ -2265,9 +2249,9 @@ base64-js@^1.3.1: integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== baseline-browser-mapping@^2.9.0: - version "2.9.17" - resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.17.tgz#9d6019766cd7eba738cb5f32c84b9f937cc87780" - integrity sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ== + version "2.9.19" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz#3e508c43c46d961eb4d7d2e5b8d1dd0f9ee4f488" + integrity sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg== binary-extensions@^2.0.0: version "2.3.0" @@ -2366,9 +2350,9 @@ camelcase-css@^2.0.1: integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== caniuse-lite@^1.0.30001297, caniuse-lite@^1.0.30001759: - version "1.0.30001765" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001765.tgz#4a78d8a797fd4124ebaab2043df942eb091648ee" - integrity sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ== + version "1.0.30001770" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz#4dc47d3b263a50fbb243448034921e0a88591a84" + integrity sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw== chalk@^4.1.0: version "4.1.2" @@ -2473,16 +2457,16 @@ confbox@^0.1.8: integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== confbox@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.2.tgz#8652f53961c74d9e081784beed78555974a9c110" - integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ== + version "0.2.4" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.4.tgz#592e7be71f882a4a874e3c88f0ac1ef6f7da1ce5" + integrity sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ== convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -core-js-compat@^3.43.0: +core-js-compat@^3.48.0: version "3.48.0" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.48.0.tgz#7efbe1fc1cbad44008190462217cc5558adaeaa6" integrity sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q== @@ -2666,9 +2650,9 @@ ejs@^3.1.6: jake "^10.8.5" electron-to-chromium@^1.5.263: - version "1.5.277" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.277.tgz#7164191a07bf32a7e646e68334f402dd60629821" - integrity sha512-wKXFZw4erWmmOz5N/grBoJ2XrNJGDFMu2+W5ACHza5rHtvsqrK4gb6rnLC7XxKB9WlJ+RmyQatuEXmtm86xbnw== + version "1.5.286" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz#142be1ab5e1cd5044954db0e5898f60a4960384e" + integrity sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A== engine.io-client@~6.5.2: version "6.5.4" @@ -2702,7 +2686,7 @@ entities@^4.4.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== -entities@^7.0.0: +entities@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/entities/-/entities-7.0.1.tgz#26e8a88889db63417dcb9a1e79a3f1bc92b5976b" integrity sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA== @@ -2955,40 +2939,42 @@ fraction.js@^4.1.2: integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== frappe-ui@^0.1.261: - version "0.1.261" - resolved "https://registry.yarnpkg.com/frappe-ui/-/frappe-ui-0.1.261.tgz#d6919c713a37ed8a2bdb667707dba9ece4956c6d" - integrity sha512-sEdEAgjAkrTERYWk5HBOQuKa7/xuex/X8/Y/hCYFbEThwwy2ZWmQOCsTNyOCjXAn7lyV49Ues/TW01koIq/ysQ== + version "0.1.262" + resolved "https://registry.yarnpkg.com/frappe-ui/-/frappe-ui-0.1.262.tgz#b88416aac76fdce183f95f2ac935ce65ffb2b2eb" + integrity sha512-KKH7LLLa3yvfM3QeLaiaSqeSS+BUdCu3+8BrvXAG09ejGU1Z6k0wXEG314J0yXxK4rLifd83zpKbtUCG9zIKFA== dependencies: + "@floating-ui/dom" "^1.7.4" "@floating-ui/vue" "^1.1.6" "@headlessui/vue" "^1.7.14" "@popperjs/core" "^2.11.2" "@tailwindcss/forms" "^0.5.3" "@tailwindcss/line-clamp" "^0.4.4" "@tailwindcss/typography" "^0.5.16" - "@tiptap/core" "^2.26.1" - "@tiptap/extension-code" "^2.26.1" - "@tiptap/extension-code-block" "^2.26.1" - "@tiptap/extension-code-block-lowlight" "^2.26.1" - "@tiptap/extension-color" "^2.26.1" - "@tiptap/extension-heading" "^2.26.1" - "@tiptap/extension-highlight" "^2.26.1" - "@tiptap/extension-image" "^2.26.1" - "@tiptap/extension-link" "^2.26.1" - "@tiptap/extension-mention" "^2.26.1" - "@tiptap/extension-placeholder" "^2.26.1" - "@tiptap/extension-table" "^2.26.1" - "@tiptap/extension-table-cell" "^2.26.1" - "@tiptap/extension-table-header" "^2.26.1" - "@tiptap/extension-table-row" "^2.26.1" - "@tiptap/extension-task-item" "^2.26.1" - "@tiptap/extension-task-list" "^2.26.1" - "@tiptap/extension-text-align" "^2.26.1" - "@tiptap/extension-text-style" "^2.26.1" - "@tiptap/extension-typography" "^2.26.1" - "@tiptap/pm" "^2.26.1" - "@tiptap/starter-kit" "^2.26.1" - "@tiptap/suggestion" "^2.26.1" - "@tiptap/vue-3" "^2.26.1" + "@tiptap/core" "^3.11.0" + "@tiptap/extension-bubble-menu" "^3.11.0" + "@tiptap/extension-code" "^3.11.0" + "@tiptap/extension-code-block" "^3.11.0" + "@tiptap/extension-code-block-lowlight" "^3.11.0" + "@tiptap/extension-color" "^3.11.0" + "@tiptap/extension-heading" "^3.11.0" + "@tiptap/extension-highlight" "^3.11.0" + "@tiptap/extension-image" "^3.11.0" + "@tiptap/extension-link" "^3.11.0" + "@tiptap/extension-list" "^3.11.0" + "@tiptap/extension-mention" "^3.11.0" + "@tiptap/extension-node-range" "^3.11.0" + "@tiptap/extension-placeholder" "^3.11.0" + "@tiptap/extension-table" "^3.11.0" + "@tiptap/extension-task-item" "^3.11.0" + "@tiptap/extension-task-list" "^3.11.0" + "@tiptap/extension-text-align" "^3.11.0" + "@tiptap/extension-text-style" "^3.11.0" + "@tiptap/extension-typography" "^3.11.0" + "@tiptap/extensions" "^3.11.0" + "@tiptap/pm" "^3.11.0" + "@tiptap/starter-kit" "^3.11.0" + "@tiptap/suggestion" "^3.11.0" + "@tiptap/vue-3" "^3.11.0" "@vueuse/core" "^10.4.1" dayjs "^1.11.13" dompurify "^3.2.6" @@ -2998,12 +2984,14 @@ frappe-ui@^0.1.261: highlight.js "^11.11.1" idb-keyval "^6.2.0" lowlight "^3.3.0" - lucide-static "^0.535.0" + lucide-static "^0.543.0" marked "^15.0.12" ora "5.4.1" prettier "^3.3.2" + prosemirror-tables "^1.8.1" radix-vue "^1.5.3" reka-ui "^2.5.0" + slugify "^1.6.6" socket.io-client "^4.5.1" tippy.js "^6.3.7" typescript "^5.0.2" @@ -3618,10 +3606,10 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lucide-static@^0.535.0: - version "0.535.0" - resolved "https://registry.yarnpkg.com/lucide-static/-/lucide-static-0.535.0.tgz#3d8ad25360d166a4f584d97f2c08fd9b24be30d7" - integrity sha512-wlYTSPpeyMjLjQ5jgSAENQwVfURVf2XHV5TDp8YPCJBEyWz+FJGuGB5LYBgOFvWIDOMW+AIoiA8sNd8My/nxlw== +lucide-static@^0.543.0: + version "0.543.0" + resolved "https://registry.yarnpkg.com/lucide-static/-/lucide-static-0.543.0.tgz#054c14493993452084ed9968a3ad912c58fec90a" + integrity sha512-k9HUQncNuOThizzuuqvgjpYPHaE3Hae89l/i+Y7BRgOvzWeqQ9Sbllin8m4NO5BP+JaaRHTzn29o4oZJJi/5uQ== lucide-vue-next@0.383.0: version "0.383.0" @@ -3655,9 +3643,9 @@ markdown-it@14.0.0: uc.micro "^2.0.0" markdown-it@^14.0.0: - version "14.1.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45" - integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== + version "14.1.1" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.1.tgz#856f90b66fc39ae70affd25c1b18b581d7deee1f" + integrity sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA== dependencies: argparse "^2.0.1" entities "^4.4.0" @@ -4024,9 +4012,9 @@ pretty-bytes@^6.0.0: integrity sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ== prosemirror-changeset@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/prosemirror-changeset/-/prosemirror-changeset-2.3.1.tgz#eee3299cfabc7a027694e9abdc4e85505e9dd5e7" - integrity sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ== + version "2.4.0" + resolved "https://registry.yarnpkg.com/prosemirror-changeset/-/prosemirror-changeset-2.4.0.tgz#8d8ea0290cb9545c298ec427ac3a8f298c39170f" + integrity sha512-LvqH2v7Q2SF6yxatuPP2e8vSUKS/L+xAU7dPDC4RMyHMhZoGDfBC74mYuyYF4gLqOEG758wajtyhNnsTkuhvng== dependencies: prosemirror-transform "^1.0.0" @@ -4092,9 +4080,9 @@ prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.2.2, prosemirror-keymap@^1.2.3: w3c-keyname "^2.2.0" prosemirror-markdown@^1.13.1: - version "1.13.3" - resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.13.3.tgz#cf38e98f10c432b906bfcc7179c2e3ab58f49362" - integrity sha512-3E+Et6cdXIH0EgN2tGYQ+EBT7N4kMiZFsW+hzx+aPtOmADDHWCdd2uUQb7yklJrfUYUOjEEu22BiN6UFgPe4cQ== + version "1.13.4" + resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.13.4.tgz#4620e6a0580cd52b5fc8e352c7e04830cd4b3048" + integrity sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw== dependencies: "@types/markdown-it" "^14.0.0" markdown-it "^14.0.0" @@ -4110,7 +4098,7 @@ prosemirror-menu@^1.2.4: prosemirror-history "^1.0.0" prosemirror-state "^1.0.0" -prosemirror-model@^1.0.0, prosemirror-model@^1.20.0, prosemirror-model@^1.21.0, prosemirror-model@^1.23.0, prosemirror-model@^1.25.0, prosemirror-model@^1.25.4: +prosemirror-model@^1.0.0, prosemirror-model@^1.20.0, prosemirror-model@^1.21.0, prosemirror-model@^1.24.1, prosemirror-model@^1.25.0, prosemirror-model@^1.25.4: version "1.25.4" resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.25.4.tgz#8ebfbe29ecbee9e5e2e4048c4fe8e363fcd56e7c" integrity sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA== @@ -4124,7 +4112,7 @@ prosemirror-schema-basic@^1.2.3: dependencies: prosemirror-model "^1.25.0" -prosemirror-schema-list@^1.4.1: +prosemirror-schema-list@^1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz#5869c8f749e8745c394548bb11820b0feb1e32f5" integrity sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q== @@ -4142,7 +4130,7 @@ prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.4.3, pr prosemirror-transform "^1.0.0" prosemirror-view "^1.27.0" -prosemirror-tables@^1.6.4: +prosemirror-tables@^1.6.4, prosemirror-tables@^1.8.1: version "1.8.5" resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz#104427012e5a5da1d2a38c122efee8d66bdd5104" integrity sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw== @@ -4168,10 +4156,10 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transfor dependencies: prosemirror-model "^1.21.0" -prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.37.0, prosemirror-view@^1.41.4: - version "1.41.5" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.41.5.tgz#3e152d14af633f2f5a73aba24e6130c63f643b2b" - integrity sha512-UDQbIPnDrjE8tqUBbPmCOZgtd75htE6W3r0JCmY9bL6W1iemDM37MZEKC49d+tdQ0v/CKx4gjxLoLsfkD2NiZA== +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.38.1, prosemirror-view@^1.41.4: + version "1.41.6" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.41.6.tgz#949d0407a91e36f6024db2191b8d3058dfd18838" + integrity sha512-mxpcDG4hNQa/CPtzxjdlir5bJFDlm0/x5nGBbStB2BWX+XOQ9M8ekEG+ojqB5BcVu2Rc80/jssCMZzSstJuSYg== dependencies: prosemirror-model "^1.20.0" prosemirror-state "^1.0.0" @@ -4312,17 +4300,17 @@ regjsparser@^0.13.0: jsesc "~3.1.0" reka-ui@^2.5.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/reka-ui/-/reka-ui-2.7.0.tgz#906697e744e9a9682f89372a46ef384d4500eae7" - integrity sha512-m+XmxQN2xtFzBP3OAdIafKq7C8OETo2fqfxcIIxYmNN2Ch3r5oAf6yEYCIJg5tL/yJU2mHqF70dCCekUkrAnXA== + version "2.8.0" + resolved "https://registry.yarnpkg.com/reka-ui/-/reka-ui-2.8.0.tgz#612023ad40c5c10999aef304f2b828cdd08da6a8" + integrity sha512-N4JOyIrmDE7w2i06WytqcV2QICubtS2PsK5Uo8FIMAgmO13KhUAgAByP26cXjjm2oF/w7rTyRs8YaqtvaBT+SA== dependencies: "@floating-ui/dom" "^1.6.13" "@floating-ui/vue" "^1.1.6" "@internationalized/date" "^3.5.0" "@internationalized/number" "^3.5.0" "@tanstack/vue-virtual" "^3.12.0" - "@vueuse/core" "^12.5.0" - "@vueuse/shared" "^12.5.0" + "@vueuse/core" "^14.1.0" + "@vueuse/shared" "^14.1.0" aria-hidden "^1.2.4" defu "^6.1.4" ohash "^2.0.11" @@ -4332,7 +4320,7 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -resolve@^1.1.7, resolve@^1.19.0, resolve@^1.22.10, resolve@^1.22.8: +resolve@^1.1.7, resolve@^1.19.0, resolve@^1.22.11, resolve@^1.22.8: version "1.22.11" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== @@ -4372,37 +4360,37 @@ rollup@^2.43.1: fsevents "~2.3.2" rollup@^4.2.0: - version "4.56.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.56.0.tgz#65959d13cfbd7e48b8868c05165b1738f0143862" - integrity sha512-9FwVqlgUHzbXtDg9RCMgodF3Ua4Na6Gau+Sdt9vyCN4RhHfVKX2DCHy3BjMLTDd47ITDhYAnTwGulWTblJSDLg== + version "4.57.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.57.1.tgz#947f70baca32db2b9c594267fe9150aa316e5a88" + integrity sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A== dependencies: "@types/estree" "1.0.8" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.56.0" - "@rollup/rollup-android-arm64" "4.56.0" - "@rollup/rollup-darwin-arm64" "4.56.0" - "@rollup/rollup-darwin-x64" "4.56.0" - "@rollup/rollup-freebsd-arm64" "4.56.0" - "@rollup/rollup-freebsd-x64" "4.56.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.56.0" - "@rollup/rollup-linux-arm-musleabihf" "4.56.0" - "@rollup/rollup-linux-arm64-gnu" "4.56.0" - "@rollup/rollup-linux-arm64-musl" "4.56.0" - "@rollup/rollup-linux-loong64-gnu" "4.56.0" - "@rollup/rollup-linux-loong64-musl" "4.56.0" - "@rollup/rollup-linux-ppc64-gnu" "4.56.0" - "@rollup/rollup-linux-ppc64-musl" "4.56.0" - "@rollup/rollup-linux-riscv64-gnu" "4.56.0" - "@rollup/rollup-linux-riscv64-musl" "4.56.0" - "@rollup/rollup-linux-s390x-gnu" "4.56.0" - "@rollup/rollup-linux-x64-gnu" "4.56.0" - "@rollup/rollup-linux-x64-musl" "4.56.0" - "@rollup/rollup-openbsd-x64" "4.56.0" - "@rollup/rollup-openharmony-arm64" "4.56.0" - "@rollup/rollup-win32-arm64-msvc" "4.56.0" - "@rollup/rollup-win32-ia32-msvc" "4.56.0" - "@rollup/rollup-win32-x64-gnu" "4.56.0" - "@rollup/rollup-win32-x64-msvc" "4.56.0" + "@rollup/rollup-android-arm-eabi" "4.57.1" + "@rollup/rollup-android-arm64" "4.57.1" + "@rollup/rollup-darwin-arm64" "4.57.1" + "@rollup/rollup-darwin-x64" "4.57.1" + "@rollup/rollup-freebsd-arm64" "4.57.1" + "@rollup/rollup-freebsd-x64" "4.57.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.57.1" + "@rollup/rollup-linux-arm-musleabihf" "4.57.1" + "@rollup/rollup-linux-arm64-gnu" "4.57.1" + "@rollup/rollup-linux-arm64-musl" "4.57.1" + "@rollup/rollup-linux-loong64-gnu" "4.57.1" + "@rollup/rollup-linux-loong64-musl" "4.57.1" + "@rollup/rollup-linux-ppc64-gnu" "4.57.1" + "@rollup/rollup-linux-ppc64-musl" "4.57.1" + "@rollup/rollup-linux-riscv64-gnu" "4.57.1" + "@rollup/rollup-linux-riscv64-musl" "4.57.1" + "@rollup/rollup-linux-s390x-gnu" "4.57.1" + "@rollup/rollup-linux-x64-gnu" "4.57.1" + "@rollup/rollup-linux-x64-musl" "4.57.1" + "@rollup/rollup-openbsd-x64" "4.57.1" + "@rollup/rollup-openharmony-arm64" "4.57.1" + "@rollup/rollup-win32-arm64-msvc" "4.57.1" + "@rollup/rollup-win32-ia32-msvc" "4.57.1" + "@rollup/rollup-win32-x64-gnu" "4.57.1" + "@rollup/rollup-win32-x64-msvc" "4.57.1" fsevents "~2.3.2" rope-sequence@^1.3.0: @@ -4543,6 +4531,11 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +slugify@^1.6.6: + version "1.6.6" + resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.6.tgz#2d4ac0eacb47add6af9e04d3be79319cbcc7924b" + integrity sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw== + socket.io-client@4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.2.tgz#f2f13f68058bd4e40f94f2a1541f275157ff2c08" @@ -5168,16 +5161,16 @@ vue3-apexcharts@1.8.0: resolved "https://registry.yarnpkg.com/vue3-apexcharts/-/vue3-apexcharts-1.8.0.tgz#1984648d966aa91bc4dc3e87fa847f5289f7f1cf" integrity sha512-5tSD4mXTBbIJ9ir+58qHE6oNtIe0RNgqIRYMKpcsIaxkKtwUww4JhvPkpUFlmiW4OJbbdklgjleXq1lfcM4gdA== -vue@^3.5.13, vue@^3.5.27: - version "3.5.27" - resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.27.tgz#e55fd941b614459ab2228489bc19d1692e05876c" - integrity sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw== +vue@^3.5.27: + version "3.5.28" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.28.tgz#067ac9313d24d517c6d59ccbd9f0f6216cbdb00f" + integrity sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg== dependencies: - "@vue/compiler-dom" "3.5.27" - "@vue/compiler-sfc" "3.5.27" - "@vue/runtime-dom" "3.5.27" - "@vue/server-renderer" "3.5.27" - "@vue/shared" "3.5.27" + "@vue/compiler-dom" "3.5.28" + "@vue/compiler-sfc" "3.5.28" + "@vue/runtime-dom" "3.5.28" + "@vue/server-renderer" "3.5.28" + "@vue/shared" "3.5.28" vuedraggable@4.1.0: version "4.1.0" diff --git a/lms/auth.py b/lms/auth.py index e84f2de4..868194d0 100644 --- a/lms/auth.py +++ b/lms/auth.py @@ -47,6 +47,7 @@ ALLOWED_PATHS = [ "/api/method/frappe.core.doctype.user.user.reset_password", "/api/method/frappe.desk.doctype.notification_log.notification_log.mark_as_read", "/api/method/frappe.desk.doctype.notification_log.notification_log.mark_all_as_read", + "/api/method/frappe.sessions.clear", ] diff --git a/lms/command_palette.py b/lms/command_palette.py index 986e1780..01bb6bc5 100644 --- a/lms/command_palette.py +++ b/lms/command_palette.py @@ -16,7 +16,7 @@ def search_sqlite(query: str): return prepare_search_results(result) -def prepare_search_results(result): +def prepare_search_results(result: dict): groups = get_grouped_results(result) out = [] diff --git a/lms/hooks.py b/lms/hooks.py index 2a289ce1..71d47d8d 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -277,3 +277,4 @@ add_to_apps_screen = [ sqlite_search = ["lms.sqlite.LearningSearch"] auth_hooks = ["lms.auth.authenticate"] +require_type_annotated_api_methods = True diff --git a/lms/install.py b/lms/install.py index f2bd0575..9862f0dd 100644 --- a/lms/install.py +++ b/lms/install.py @@ -7,6 +7,7 @@ from lms.lms.api import give_discussions_permission def after_install(): create_batch_source() give_discussions_permission() + give_user_list_permission() def after_sync(): @@ -27,13 +28,6 @@ def create_lms_roles(): create_lms_student_role() -def delete_lms_roles(): - roles = ["Course Creator", "Moderator"] - for role in roles: - if frappe.db.exists("Role", role): - frappe.db.delete("Role", role) - - def create_course_creator_role(): if frappe.db.exists("Role", "Course Creator"): frappe.db.set_value("Role", "Course Creator", "desk_access", 0) @@ -185,3 +179,36 @@ def give_lms_roles_to_admin(): doc.parentfield = "roles" doc.role = role doc.save() + + +def give_user_list_permission(): + doctype = "User" + roles = ["Course Creator", "Moderator", "Batch Evaluator"] + for role in roles: + permlevel = 0 + create_role(doctype, role, permlevel) + create_role(doctype, "System Manager", 1) + + +def create_role(doctype, role, permlevel): + if not frappe.db.exists("Custom DocPerm", {"parent": doctype, "role": role, "permlevel": permlevel}): + doc = frappe.new_doc("Custom DocPerm") + doc.update( + { + "doctype": "Custom DocPerm", + "parent": doctype, + "role": role, + "read": 1, + "write": 1 if role in ["Moderator", "System Manager"] else 0, + "create": 1 if role == "Moderator" else 0, + "permlevel": permlevel, + } + ) + doc.save() + + +def delete_lms_roles(): + roles = ["Course Creator", "Moderator", "Batch Evaluator", "LMS Student"] + for role in roles: + if frappe.db.exists("Role", role): + frappe.db.delete("Role", role) diff --git a/lms/job/doctype/job_opportunity/job_opportunity.py b/lms/job/doctype/job_opportunity/job_opportunity.py index da9a357b..bc8d3e36 100644 --- a/lms/job/doctype/job_opportunity/job_opportunity.py +++ b/lms/job/doctype/job_opportunity/job_opportunity.py @@ -35,7 +35,7 @@ def update_job_openings(): @frappe.whitelist() -def report(job, reason): +def report(job: str, reason: str): system_managers = get_system_managers(only_name=True) user = frappe.db.get_value("User", frappe.session.user, "full_name") subject = _("User {0} has reported the job post {1}").format(user, job) diff --git a/lms/lms/api.py b/lms/lms/api.py index 931b23b7..d9849999 100644 --- a/lms/lms/api.py +++ b/lms/lms/api.py @@ -80,7 +80,7 @@ def get_translations(): @frappe.whitelist() -def validate_billing_access(billing_type, name): +def validate_billing_access(billing_type: str, name: str): doctype = "LMS Batch" if billing_type == "batch" else "LMS Course" access, message = verify_billing_access(doctype, name, billing_type) @@ -160,7 +160,7 @@ def verify_billing_access(doctype, name, billing_type): @frappe.whitelist(allow_guest=True) -def get_job_details(job): +def get_job_details(job: str): return frappe.db.get_value( "Job Opportunity", job, @@ -183,7 +183,7 @@ def get_job_details(job): @frappe.whitelist(allow_guest=True) -def get_job_opportunities(filters=None, orFilters=None): +def get_job_opportunities(filters: dict = None, orFilters: dict = None): if not filters: filters = {} @@ -257,7 +257,7 @@ def get_branding(): @frappe.whitelist() -def get_unsplash_photos(keyword=None): +def get_unsplash_photos(keyword: str = None): from lms.unsplash import get_by_keyword, get_list if keyword: @@ -267,7 +267,7 @@ def get_unsplash_photos(keyword=None): @frappe.whitelist() -def get_evaluator_details(evaluator): +def get_evaluator_details(evaluator: str): frappe.only_for("Batch Evaluator") if not frappe.db.exists("Google Calendar", {"user": evaluator}): @@ -294,7 +294,7 @@ def get_evaluator_details(evaluator): @frappe.whitelist() -def get_certified_participants(filters=None, start=0, page_length=100): +def get_certified_participants(filters: dict = None, start: int = 0, page_length: int = 100): query = get_certification_query(filters) query = query.orderby("issue_date", order=frappe.qb.desc).offset(start).limit(page_length) participants = query.run(as_dict=True) @@ -306,7 +306,7 @@ def get_certified_participants(filters=None, start=0, page_length=100): return participants -def get_certified_participant_details(member): +def get_certified_participant_details(member: str): count = frappe.db.count("LMS Certificate", {"member": member}) details = frappe.db.get_value( "User", @@ -318,7 +318,7 @@ def get_certified_participant_details(member): return details -def get_certification_query(filters): +def get_certification_query(filters: dict = None): Certificate = frappe.qb.DocType("LMS Certificate") User = frappe.qb.DocType("User") @@ -348,7 +348,7 @@ def get_certification_query(filters): @frappe.whitelist() -def get_count_of_certified_members(filters=None): +def get_count_of_certified_members(filters: dict = None): query = get_certification_query(filters) result = query.run(as_dict=True) return len(result) or 0 @@ -424,7 +424,7 @@ def get_sidebar_settings(): @frappe.whitelist() -def update_sidebar_item(webpage, icon): +def update_sidebar_item(webpage: str, icon: str): frappe.only_for("Moderator") filters = { "web_page": webpage, @@ -443,7 +443,7 @@ def update_sidebar_item(webpage, icon): @frappe.whitelist() -def delete_sidebar_item(webpage): +def delete_sidebar_item(webpage: str): frappe.only_for("Moderator") return frappe.db.delete( "LMS Sidebar Item", @@ -457,7 +457,7 @@ def delete_sidebar_item(webpage): @frappe.whitelist() -def delete_lesson(lesson, chapter): +def delete_lesson(lesson: str, chapter: str): course = frappe.db.get_value("Course Chapter", chapter, "course") if not can_modify_course(course): frappe.throw(_("You do not have permission to delete this lesson."), frappe.PermissionError) @@ -477,7 +477,7 @@ def delete_lesson(lesson, chapter): @frappe.whitelist() -def update_lesson_index(lesson, sourceChapter, targetChapter, idx): +def update_lesson_index(lesson: str, sourceChapter: str, targetChapter: str, idx: int): course = frappe.db.get_value("Course Chapter", sourceChapter, "course") if not can_modify_course(course): frappe.throw(_("You do not have permission to modify this lesson."), frappe.PermissionError) @@ -488,7 +488,7 @@ def update_lesson_index(lesson, sourceChapter, targetChapter, idx): update_target_chapter(lesson, targetChapter, idx) -def update_source_chapter(lesson, chapter, idx, hasMoved=False): +def update_source_chapter(lesson: str, chapter: str, idx: int, hasMoved: bool = False): lessons = frappe.get_all( "Lesson Reference", { @@ -507,7 +507,7 @@ def update_source_chapter(lesson, chapter, idx, hasMoved=False): update_index(lessons, chapter) -def update_target_chapter(lesson, chapter, idx): +def update_target_chapter(lesson: str, chapter: str, idx: int): lessons = frappe.get_all( "Lesson Reference", { @@ -531,7 +531,7 @@ def update_target_chapter(lesson, chapter, idx): update_index(lessons, chapter) -def update_index(lessons, chapter): +def update_index(lessons: list, chapter: str): for row in lessons: frappe.db.set_value( "Lesson Reference", {"lesson": row, "parent": chapter}, "idx", lessons.index(row) + 1 @@ -539,7 +539,7 @@ def update_index(lessons, chapter): @frappe.whitelist() -def update_chapter_index(chapter, course, idx): +def update_chapter_index(chapter: str, course: str, idx: int): """Update the index of a chapter within a course""" if not can_modify_course(course): @@ -562,7 +562,7 @@ def update_chapter_index(chapter, course, idx): @frappe.whitelist() -def get_members(start=0, search=""): +def get_members(start: int = 0, search: str = None): frappe.only_for(["Moderator"]) filters = {"enabled": 1, "name": ["not in", ["Administrator", "Guest"]]} or_filters = {} @@ -616,16 +616,16 @@ def check_app_permission(): @frappe.whitelist() def save_evaluation_details( - member, - course, - batch_name, - evaluator, - date, - start_time, - end_time, - status, - rating, - summary, + member: str, + course: str, + date: str, + start_time: str, + end_time: str, + status: str, + batch_name: str = None, + evaluator: str = None, + rating: float = 0, + summary: str = None, ): """ Save evaluation details for a member against a course. @@ -662,14 +662,14 @@ def save_evaluation_details( @frappe.whitelist() def save_certificate_details( - member, - course, - batch_name, - evaluator, - issue_date, - expiry_date, - template, - published=True, + member: str, + issue_date: str, + template: str, + course: str = None, + batch_name: str = None, + evaluator: str = None, + expiry_date: str = None, + published: bool = True, ): """ Save certificate details for a member against a course. @@ -703,14 +703,14 @@ def save_certificate_details( @frappe.whitelist() -def delete_documents(doctype, documents): +def delete_documents(doctype: str, documents: list): frappe.only_for("Moderator") for doc in documents: frappe.delete_doc(doctype, doc) @frappe.whitelist() -def get_payment_gateway_details(payment_gateway): +def get_payment_gateway_details(payment_gateway: str): frappe.only_for("Moderator") gateway = frappe.get_doc("Payment Gateway", payment_gateway) @@ -741,7 +741,7 @@ def get_payment_gateway_details(payment_gateway): } -def get_transformed_fields(meta, data=None): +def get_transformed_fields(meta: list, data: dict = None): transformed_fields = [] for row in meta: if row.fieldtype not in ["Column Break", "Section Break"]: @@ -766,7 +766,7 @@ def get_transformed_fields(meta, data=None): @frappe.whitelist() -def get_new_gateway_fields(doctype): +def get_new_gateway_fields(doctype: str): frappe.only_for("Moderator") try: meta = frappe.get_meta(doctype).fields @@ -797,7 +797,7 @@ def update_course_statistics(): @frappe.whitelist() -def get_announcements(batch): +def get_announcements(batch: str): roles = frappe.get_roles() is_batch_student = frappe.db.exists( "LMS Batch Enrollment", {"batch": batch, "member": frappe.session.user} @@ -835,7 +835,7 @@ def get_announcements(batch): @frappe.whitelist() -def delete_course(course): +def delete_course(course: str): if not can_modify_course(course): frappe.throw(_("You do not have permission to delete this course."), frappe.PermissionError) @@ -872,7 +872,7 @@ def delete_course(course): @frappe.whitelist() -def delete_batch(batch): +def delete_batch(batch: str): if not can_modify_batch(batch): frappe.throw(_("You do not have permission to delete this batch."), frappe.PermissionError) @@ -885,7 +885,7 @@ def delete_batch(batch): frappe.db.delete("LMS Batch", batch) -def delete_batch_discussions(batch): +def delete_batch_discussions(batch: str): topics = frappe.get_all( "Discussion Topic", {"reference_doctype": "LMS Batch", "reference_docname": batch}, @@ -918,7 +918,9 @@ def give_discussions_permission(): @frappe.whitelist() -def upsert_chapter(title, course, is_scorm_package, scorm_package, name=None): +def upsert_chapter( + title: str, course: str, is_scorm_package: bool, scorm_package: dict = None, name: str = None +): if not can_modify_course(course): frappe.throw(_("You do not have permission to modify this chapter."), frappe.PermissionError) @@ -951,7 +953,7 @@ def upsert_chapter(title, course, is_scorm_package, scorm_package, name=None): return chapter -def extract_package(course, title, scorm_package): +def extract_package(course: str, title: str, scorm_package: dict): package = frappe.get_doc("File", scorm_package.name) zip_path = package.get_full_path() # check_for_malicious_code(zip_path) @@ -983,7 +985,7 @@ def check_for_malicious_code(zip_path): frappe.throw(_("Suspicious pattern found in {0}: {1}").format(file_name, pattern)) -def get_manifest_file(extract_path): +def get_manifest_file(extract_path: str): manifest_file = None for root, _dirs, files in os.walk(extract_path): for file in files: @@ -995,7 +997,7 @@ def get_manifest_file(extract_path): return manifest_file -def get_launch_file(extract_path): +def get_launch_file(extract_path: str): launch_file = None manifest_file = get_manifest_file(extract_path) @@ -1018,7 +1020,7 @@ def get_launch_file(extract_path): return launch_file -def add_lesson(title, chapter, course, idx): +def add_lesson(title: str, chapter: str, course: str, idx: int): lesson = frappe.new_doc("Course Lesson") lesson.update( { @@ -1043,7 +1045,7 @@ def add_lesson(title, chapter, course, idx): @frappe.whitelist() -def delete_chapter(chapter): +def delete_chapter(chapter: str): course = frappe.db.get_value("Course Chapter", chapter, "course") if not can_modify_course(course): frappe.throw(_("You do not have permission to delete this chapter."), frappe.PermissionError) @@ -1074,14 +1076,14 @@ def delete_chapter(chapter): i += 1 -def delete_scorm_package(scorm_package_path): +def delete_scorm_package(scorm_package_path: str): scorm_package_path = frappe.get_site_path("public", scorm_package_path[1:]) if os.path.exists(scorm_package_path): shutil.rmtree(scorm_package_path) @frappe.whitelist() -def mark_lesson_progress(course, chapter_number, lesson_number): +def mark_lesson_progress(course: str, chapter_number: int, lesson_number: int): chapter_name = frappe.get_value("Chapter Reference", {"parent": course, "idx": chapter_number}, "chapter") lesson_name = frappe.get_value( "Lesson Reference", {"parent": chapter_name, "idx": lesson_number}, "lesson" @@ -1090,7 +1092,7 @@ def mark_lesson_progress(course, chapter_number, lesson_number): @frappe.whitelist() -def get_heatmap_data(member, base_days=200): +def get_heatmap_data(member: str, base_days: int = 200): if not (has_course_instructor_role() or has_moderator_role() or has_evaluator_role()): frappe.throw(_("You do not have permission to access heatmap data."), frappe.PermissionError) @@ -1114,7 +1116,7 @@ def get_heatmap_data(member, base_days=200): } -def calculate_date_ranges(base_days): +def calculate_date_ranges(base_days: int): today = format_date(now(), "YYYY-MM-dd") day_today = get_datetime(today).strftime("%w") padding_end = 6 - cint(day_today) @@ -1128,11 +1130,11 @@ def calculate_date_ranges(base_days): return base_date, start_date, number_of_days, days -def initialize_date_count(days): +def initialize_date_count(days: list): return {format_date(day, "YYYY-MM-dd"): 0 for day in days} -def fetch_activity_data(member, start_date): +def fetch_activity_data(member: str, start_date: str): lesson_completions = frappe.get_all( "LMS Course Progress", fields=["creation"], @@ -1154,14 +1156,14 @@ def fetch_activity_data(member, start_date): return lesson_completions, quiz_submissions, assignment_submissions -def count_dates(data, date_count): +def count_dates(data: list, date_count: dict): for entry in data: date = format_date(entry.creation, "YYYY-MM-dd") if date in date_count: date_count[date] += 1 -def prepare_heatmap_data(start_date, number_of_days, date_count): +def prepare_heatmap_data(start_date: str, number_of_days: int, date_count: dict): days_of_week = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] heatmap_data = {day: [] for day in days_of_week} week_count = -(number_of_days // -7) @@ -1198,13 +1200,13 @@ def prepare_heatmap_data(start_date, number_of_days, date_count): return formatted_heatmap_data, labels, total_activities, week_count -def get_week_difference(start_date, current_date): +def get_week_difference(start_date: str, current_date: str) -> int: diff_in_days = date_diff(current_date, start_date) return diff_in_days // 7 @frappe.whitelist() -def get_notifications(filters): +def get_notifications(filters: dict = None): filters = frappe._dict(filters or {}) filters.for_user = frappe.session.user notifications = frappe.get_all( @@ -1232,7 +1234,7 @@ def get_notifications(filters): return notifications -def update_user_details(notification): +def update_user_details(notification: dict) -> dict: if ( notification.document_details and len(notification.document_details.get("instructors", [])) @@ -1247,7 +1249,7 @@ def update_user_details(notification): return notification -def is_mention(notification): +def is_mention(notification: dict) -> bool: if notification.type == "Mention": return True if "mentioned you" in notification.subject.lower(): @@ -1255,7 +1257,7 @@ def is_mention(notification): return False -def update_document_details(notification): +def update_document_details(notification: dict) -> dict: if notification.document_type == "LMS Course": details = frappe.db.get_value( "LMS Course", notification.document_name, ["title", "video_link", "short_introduction"], as_dict=1 @@ -1304,8 +1306,9 @@ def get_lms_settings(): @frappe.whitelist() -def cancel_evaluation(evaluation): +def cancel_evaluation(evaluation: dict): evaluation = frappe._dict(evaluation) + print(evaluation.member, frappe.session.user) if evaluation.member != frappe.session.user: frappe.throw(_("You do not have permission to cancel this evaluation."), frappe.PermissionError) @@ -1336,7 +1339,7 @@ def cancel_evaluation(evaluation): @frappe.whitelist() -def get_certification_details(course): +def get_certification_details(course: str): membership = None filters = {"course": course, "member": frappe.session.user} @@ -1364,7 +1367,7 @@ def get_certification_details(course): @frappe.whitelist() -def save_role(user, role, value): +def save_role(user: str, role: str, value: int): frappe.only_for("Moderator") if cint(value): doc = frappe.get_doc( @@ -1384,7 +1387,7 @@ def save_role(user, role, value): @frappe.whitelist() -def add_an_evaluator(email): +def add_an_evaluator(email: str): frappe.only_for("Moderator") if not frappe.db.exists("User", email): user = frappe.new_doc("User") @@ -1406,7 +1409,7 @@ def add_an_evaluator(email): @frappe.whitelist() -def capture_user_persona(responses): +def capture_user_persona(responses: str): frappe.only_for("System Manager") data = frappe.parse_json(responses) data = json.dumps(data) @@ -1420,7 +1423,7 @@ def capture_user_persona(responses): @frappe.whitelist() -def get_meta_info(type, route): +def get_meta_info(type: str, route: str): if frappe.db.exists("Website Meta Tag", {"parent": f"{type}/{route}"}): meta_tags = frappe.get_all( "Website Meta Tag", @@ -1436,7 +1439,7 @@ def get_meta_info(type, route): @frappe.whitelist() -def update_meta_info(meta_type, route, meta_tags): +def update_meta_info(meta_type: str, route: str, meta_tags: list): frappe.only_for(["Course Creator", "Batch Evaluator", "Moderator"]) validate_meta_data_permissions(meta_type) validate_meta_tags(meta_tags) @@ -1473,12 +1476,12 @@ def update_meta_info(meta_type, route, meta_tags): create_meta_tag(tag_properties) -def validate_meta_tags(meta_tags): +def validate_meta_tags(meta_tags: list): if not isinstance(meta_tags, list): frappe.throw(_("Meta tags should be a list.")) -def create_meta(parent_name, tag_properties): +def create_meta(parent_name: str, tag_properties: dict): route_meta = frappe.new_doc("Website Route Meta") route_meta.update( { @@ -1489,13 +1492,13 @@ def create_meta(parent_name, tag_properties): route_meta.insert() -def create_meta_tag(tag_properties): +def create_meta_tag(tag_properties: dict): new_tag = frappe.new_doc("Website Meta Tag") new_tag.update(tag_properties) new_tag.insert() -def validate_meta_data_permissions(meta_type): +def validate_meta_data_permissions(meta_type: str): roles = frappe.get_roles() if meta_type == "courses": @@ -1508,14 +1511,15 @@ def validate_meta_data_permissions(meta_type): @frappe.whitelist() -def create_programming_exercise_submission(exercise, submission, code, test_cases): +def create_programming_exercise_submission(exercise: str, submission: str, code: str, test_cases: list): + frappe.only_for(["Moderator", "Course Creator", "Batch Evaluator"]) if submission == "new": return make_new_exercise_submission(exercise, code, test_cases) else: update_exercise_submission(submission, code, test_cases) -def make_new_exercise_submission(exercise, code, test_cases): +def make_new_exercise_submission(exercise: str, code: str, test_cases: list): submission = frappe.new_doc("LMS Programming Exercise Submission") submission.exercise = exercise submission.member = frappe.session.user @@ -1537,7 +1541,7 @@ def make_new_exercise_submission(exercise, code, test_cases): return submission.name -def update_exercise_submission(submission, code, test_cases): +def update_exercise_submission(submission: str, code: str, test_cases: list): member = frappe.db.get_value("LMS Programming Exercise Submission", submission, "member") if member != frappe.session.user: frappe.throw(_("You do not have permission to update this submission."), frappe.PermissionError) @@ -1547,7 +1551,7 @@ def update_exercise_submission(submission, code, test_cases): frappe.db.set_value("LMS Programming Exercise Submission", submission, {"status": status, "code": code}) -def get_exercise_status(test_cases): +def get_exercise_status(test_cases: list): if not test_cases: return "Failed" @@ -1557,7 +1561,7 @@ def get_exercise_status(test_cases): return "Failed" -def update_test_cases(test_cases, submission): +def update_test_cases(test_cases: list, submission: str): frappe.db.delete("LMS Test Case Submission", {"parent": submission}) for row in test_cases: test_case = frappe.new_doc("LMS Test Case Submission") @@ -1576,7 +1580,7 @@ def update_test_cases(test_cases, submission): @frappe.whitelist() -def track_video_watch_duration(lesson, videos): +def track_video_watch_duration(lesson: str, videos: list): """ Track the watch duration of videos in a lesson. """ @@ -1603,7 +1607,7 @@ def track_video_watch_duration(lesson, videos): track_new_watch_time(lesson, video) -def track_new_watch_time(lesson, video): +def track_new_watch_time(lesson: str, video: dict): doc = frappe.new_doc("LMS Video Watch Duration") doc.lesson = lesson doc.source = video.get("source") @@ -1613,7 +1617,7 @@ def track_new_watch_time(lesson, video): @frappe.whitelist() -def get_course_progress_distribution(course): +def get_course_progress_distribution(course: str): if not can_modify_course(course): frappe.throw( _("You do not have permission to access this course's progress data."), frappe.PermissionError @@ -1636,14 +1640,14 @@ def get_course_progress_distribution(course): } -def get_average_course_progress(progress_list): +def get_average_course_progress(progress_list: list): if not progress_list: return 0 average_progress = sum(progress_list) / len(progress_list) return flt(average_progress, frappe.get_system_settings("float_precision") or 3) -def get_progress_distribution(progressList): +def get_progress_distribution(progressList: list): distribution = [ { "name": "Just Started (0-30%)", @@ -1690,7 +1694,7 @@ def get_pwa_manifest(): @frappe.whitelist() -def get_profile_details(username): +def get_profile_details(username: str): details = frappe.db.get_value( "User", {"username": username}, @@ -1729,7 +1733,7 @@ def get_streak_info(): } -def fetch_activity_dates(user): +def fetch_activity_dates(user: str): doctypes = [ "LMS Course Progress", "LMS Quiz Submission", @@ -1744,7 +1748,7 @@ def fetch_activity_dates(user): return sorted({d.date() if hasattr(d, "date") else d for d in all_dates}) -def calculate_streaks(all_dates): +def calculate_streaks(all_dates: list): streak = 0 longest_streak = 0 prev_day = None @@ -1768,7 +1772,7 @@ def calculate_streaks(all_dates): return streak, longest_streak -def calculate_current_streak(all_dates, streak): +def calculate_current_streak(all_dates: list, streak: int): if not all_dates: return 0 @@ -2034,8 +2038,8 @@ def get_upcoming_batches(): @frappe.whitelist() -def delete_programming_exercise(exercise): - frappe.only_for(["Moderator", "Course Creator"]) +def delete_programming_exercise(exercise: str): + frappe.only_for(["Moderator", "Course Creator", "Batch Evaluator"]) frappe.db.delete("LMS Programming Exercise Submission", {"exercise": exercise}) frappe.db.delete("LMS Programming Exercise", exercise) diff --git a/lms/lms/doctype/course_evaluator/course_evaluator.py b/lms/lms/doctype/course_evaluator/course_evaluator.py index e567dfca..fa127395 100644 --- a/lms/lms/doctype/course_evaluator/course_evaluator.py +++ b/lms/lms/doctype/course_evaluator/course_evaluator.py @@ -58,7 +58,7 @@ class CourseEvaluator(Document): @frappe.whitelist() -def get_schedule(course, batch=None): +def get_schedule(course: str, batch: str = None): evaluator = get_evaluator(course, batch) start_date = nowdate() end_date = get_schedule_range_end_date(start_date, batch) diff --git a/lms/lms/doctype/course_lesson/course_lesson.py b/lms/lms/doctype/course_lesson/course_lesson.py index 28105002..e891b9b0 100644 --- a/lms/lms/doctype/course_lesson/course_lesson.py +++ b/lms/lms/doctype/course_lesson/course_lesson.py @@ -46,7 +46,7 @@ class CourseLesson(Document): @frappe.whitelist() -def save_progress(lesson, course, scorm_details=None): +def save_progress(lesson: str, course: str, scorm_details: dict = None): """ Note: Pass the argument scorm_details as a dict if it is SCORM related save_progress """ diff --git a/lms/lms/doctype/lms_badge/lms_badge.py b/lms/lms/doctype/lms_badge/lms_badge.py index fe1a611b..4ca727f7 100644 --- a/lms/lms/doctype/lms_badge/lms_badge.py +++ b/lms/lms/doctype/lms_badge/lms_badge.py @@ -61,7 +61,7 @@ def eval_condition(doc, condition): @frappe.whitelist() -def assign_badge(badge): +def assign_badge(badge: str, user: str): badge = frappe._dict(json.loads(badge)) if not badge.event == "Auto Assign": return diff --git a/lms/lms/doctype/lms_batch/lms_batch.js b/lms/lms/doctype/lms_batch/lms_batch.js index dbed92c9..d6fa873e 100644 --- a/lms/lms/doctype/lms_batch/lms_batch.js +++ b/lms/lms/doctype/lms_batch/lms_batch.js @@ -12,6 +12,14 @@ frappe.ui.form.on("LMS Batch", { }; }); + frm.set_query("course", "courses", function () { + return { + filters: { + published: 1, + }, + }; + }); + frm.set_query("assessment_type", "assessment", function () { let doctypes = ["LMS Quiz", "LMS Assignment"]; return { diff --git a/lms/lms/doctype/lms_batch/lms_batch.py b/lms/lms/doctype/lms_batch/lms_batch.py index b65fdf30..4da344da 100644 --- a/lms/lms/doctype/lms_batch/lms_batch.py +++ b/lms/lms/doctype/lms_batch/lms_batch.py @@ -203,15 +203,15 @@ def send_system_notification_for_published_batch(batch): @frappe.whitelist() def create_live_class( - batch_name, - zoom_account, - title, - duration, - date, - time, - timezone, - auto_recording, - description=None, + batch_name: str, + zoom_account: str, + title: str, + duration: int, + date: str, + time: str, + timezone: str, + auto_recording: str, + description: str = None, ): payload = { "topic": title, @@ -280,7 +280,7 @@ def authenticate(zoom_account): @frappe.whitelist() -def get_batch_timetable(batch): +def get_batch_timetable(batch: str): timetable = frappe.get_all( "LMS Batch Timetable", filters={"parent": batch}, diff --git a/lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py b/lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py index c1b4a75f..351d0f0c 100644 --- a/lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py +++ b/lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py @@ -106,7 +106,7 @@ class LMSBatchEnrollment(Document): @frappe.whitelist() -def send_confirmation_email(doc): +def send_confirmation_email(doc: Document): if isinstance(doc, str): doc = frappe._dict(json.loads(doc)) diff --git a/lms/lms/doctype/lms_certificate/lms_certificate.py b/lms/lms/doctype/lms_certificate/lms_certificate.py index ec9f5231..ca35d11a 100644 --- a/lms/lms/doctype/lms_certificate/lms_certificate.py +++ b/lms/lms/doctype/lms_certificate/lms_certificate.py @@ -123,7 +123,7 @@ def is_certified(course): @frappe.whitelist() -def create_certificate(course): +def create_certificate(course: str): if is_certified(course): return frappe.db.get_value( "LMS Certificate", certificate, ["name", "course", "template"], as_dict=True diff --git a/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.py b/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.py index 6e4c8cfa..d8589108 100644 --- a/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.py +++ b/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.py @@ -25,7 +25,7 @@ def has_website_permission(doc, ptype, user, verbose=False): @frappe.whitelist() -def create_lms_certificate(source_name, target_doc=None): +def create_lms_certificate(source_name: str, target_doc: dict = None): doc = get_mapped_doc( "LMS Certificate Evaluation", source_name, diff --git a/lms/lms/doctype/lms_certificate_request/lms_certificate_request.py b/lms/lms/doctype/lms_certificate_request/lms_certificate_request.py index 33a781ce..4e7b93b5 100644 --- a/lms/lms/doctype/lms_certificate_request/lms_certificate_request.py +++ b/lms/lms/doctype/lms_certificate_request/lms_certificate_request.py @@ -174,7 +174,7 @@ def schedule_evals(): @frappe.whitelist() -def setup_calendar_event(eval): +def setup_calendar_event(eval: str): if isinstance(eval, str): eval = frappe._dict(json.loads(eval)) @@ -186,7 +186,7 @@ def setup_calendar_event(eval): update_meeting_details(eval, event, calendar) -def create_event(eval): +def create_event(eval: dict): event = frappe.get_doc( { "doctype": "Event", @@ -199,7 +199,7 @@ def create_event(eval): return event -def add_participants(eval, event): +def add_participants(eval: dict, event: Document): participants = [eval.member, eval.evaluator] for participant in participants: contact_name = frappe.db.get_value("Contact", {"email_id": participant}, "name") @@ -216,7 +216,7 @@ def add_participants(eval, event): ).save() -def update_meeting_details(eval, event, calendar): +def update_meeting_details(eval: dict, event: Document, calendar: str): event.reload() event.update( { @@ -232,7 +232,7 @@ def update_meeting_details(eval, event, calendar): @frappe.whitelist() -def create_lms_certificate_evaluation(source_name, target_doc=None): +def create_lms_certificate_evaluation(source_name: str, target_doc: dict = None): frappe.only_for(["Moderator", "Batch Evaluator", "System Manager"]) doc = get_mapped_doc( "LMS Certificate Request", diff --git a/lms/lms/doctype/lms_enrollment/lms_enrollment.py b/lms/lms/doctype/lms_enrollment/lms_enrollment.py index 9145f72e..e2d39429 100644 --- a/lms/lms/doctype/lms_enrollment/lms_enrollment.py +++ b/lms/lms/doctype/lms_enrollment/lms_enrollment.py @@ -8,9 +8,15 @@ from frappe.utils import ceil class LMSEnrollment(Document): - def before_insert(self): + def validate(self): self.validate_duplicate_enrollment() self.validate_course_enrollment_eligibility() + self.validate_owner() + + def validate_owner(self): + """Makes the member as the owner of the document so that users can update their progress""" + if self.owner != self.member: + self.owner = self.member def on_update(self): update_program_progress(self.member) @@ -45,7 +51,7 @@ class LMSEnrollment(Document): if self.enrollment_from_batch: return - if not course_details.published: + if not course_details.published and not is_admin(): frappe.throw(_("You cannot enroll in an unpublished course.")) if course_details.paid_course: diff --git a/lms/lms/doctype/lms_quiz/lms_quiz.py b/lms/lms/doctype/lms_quiz/lms_quiz.py index fc1ca4b0..9837e125 100644 --- a/lms/lms/doctype/lms_quiz/lms_quiz.py +++ b/lms/lms/doctype/lms_quiz/lms_quiz.py @@ -93,7 +93,7 @@ class LMSQuiz(Document): return result[0] -def set_total_marks(questions): +def set_total_marks(questions: list) -> int: marks = 0 for question in questions: marks += question.get("marks") @@ -101,7 +101,7 @@ def set_total_marks(questions): @frappe.whitelist() -def quiz_summary(quiz, results): +def quiz_summary(quiz: str, results: str): results = results and json.loads(results) percentage = 0 @@ -141,7 +141,7 @@ def quiz_summary(quiz, results): } -def process_results(results, quiz_details): +def process_results(results: list, quiz_details: dict): score = 0 is_open_ended = False @@ -188,7 +188,7 @@ def process_results(results, quiz_details): } -def _save_file(match): +def _save_file(match: re.Match) -> str: data = match.group(1).split("data:")[1] headers, content = data.split(",") mtype = headers.split(";", 1)[0] @@ -231,7 +231,7 @@ def get_corrupted_image_msg(): return _("Image: Corrupted Data Stream") -def create_submission(quiz, results, score_out_of, passing_percentage): +def create_submission(quiz: str, results: list, score_out_of: int, passing_percentage: float): submission = frappe.new_doc("LMS Quiz Submission") # Score and percentage are calculated by the controller function submission.update( @@ -250,7 +250,7 @@ def create_submission(quiz, results, score_out_of, passing_percentage): return submission -def save_progress_after_quiz(quiz_details, percentage): +def save_progress_after_quiz(quiz_details: dict, percentage: float): if percentage >= quiz_details.passing_percentage and quiz_details.lesson and quiz_details.course: save_progress(quiz_details.lesson, quiz_details.course) elif not quiz_details.passing_percentage: @@ -258,7 +258,7 @@ def save_progress_after_quiz(quiz_details, percentage): @frappe.whitelist() -def check_answer(question, type, answers): +def check_answer(question: str, type: str, answers: str): answers = json.loads(answers) if type == "Choices": return check_choice_answers(question, answers) @@ -266,7 +266,7 @@ def check_answer(question, type, answers): return check_input_answers(question, answers[0]) -def check_choice_answers(question, answers): +def check_choice_answers(question: str, answers: list): fields = ["multiple"] is_correct = [] for num in range(1, 5): @@ -286,7 +286,7 @@ def check_choice_answers(question, answers): return is_correct -def check_input_answers(question, answer): +def check_input_answers(question: str, answer: str): fields = [] for num in range(1, 5): fields.append(f"possibility_{cstr(num)}") diff --git a/lms/lms/payments.py b/lms/lms/payments.py index 8c2e1834..35aac722 100644 --- a/lms/lms/payments.py +++ b/lms/lms/payments.py @@ -19,18 +19,18 @@ def validate_currency(payment_gateway, currency): @frappe.whitelist() def get_payment_link( - doctype, - docname, - title, - amount, - discount_amount, - gst_amount, - currency, - address, - redirect_to, - payment_for_certificate, - coupon_code=None, - coupon=None, + doctype: str, + docname: str, + title: str, + amount: float, + discount_amount: float, + gst_amount: float, + currency: str, + address: dict, + redirect_to: str, + payment_for_certificate: int, + coupon_code: str = None, + coupon: str = None, ): payment_gateway = get_payment_gateway() address = frappe._dict(address) @@ -73,7 +73,7 @@ def get_payment_link( return url -def create_order(payment_gateway, payment_details, controller): +def create_order(payment_gateway: str, payment_details: dict, controller: object): if payment_gateway != "Razorpay": return @@ -81,7 +81,7 @@ def create_order(payment_gateway, payment_details, controller): payment_details.update({"order_id": order.get("id")}) -def get_amount_with_gst(amount, gst_amount): +def get_amount_with_gst(amount: float, gst_amount: float) -> float: amount_with_gst = 0 if gst_amount: amount_with_gst = amount + gst_amount @@ -90,17 +90,17 @@ def get_amount_with_gst(amount, gst_amount): def record_payment( - address, - doctype, - docname, - amount, - original_amount, - currency, - amount_with_gst=0, - discount_amount=0, - payment_for_certificate=0, - coupon_code=None, - coupon=None, + address: dict, + doctype: str, + docname: str, + amount: float, + original_amount: float, + currency: str, + amount_with_gst: float = 0, + discount_amount: float = 0, + payment_for_certificate: int = 0, + coupon_code: str = None, + coupon: str = None, ): address = frappe._dict(address) address_name = save_address(address) @@ -138,7 +138,7 @@ def record_payment( return payment_doc -def save_address(address): +def save_address(address: dict) -> str: filters = {"email_id": frappe.session.user} exists = frappe.db.exists("Address", filters) if exists: diff --git a/lms/lms/telemetry.py b/lms/lms/telemetry.py deleted file mode 100644 index 51dcd03b..00000000 --- a/lms/lms/telemetry.py +++ /dev/null @@ -1,12 +0,0 @@ -import frappe -from frappe.utils.telemetry import POSTHOG_HOST_FIELD, POSTHOG_PROJECT_FIELD - - -@frappe.whitelist() -def get_posthog_settings(): - return { - "posthog_project_id": frappe.conf.get(POSTHOG_PROJECT_FIELD), - "posthog_host": frappe.conf.get(POSTHOG_HOST_FIELD), - "enable_telemetry": frappe.get_system_settings("enable_telemetry"), - "telemetry_site_age": frappe.utils.telemetry.site_age(), - } diff --git a/lms/lms/user.py b/lms/lms/user.py index d6535977..4ca5cb64 100644 --- a/lms/lms/user.py +++ b/lms/lms/user.py @@ -24,7 +24,7 @@ def after_insert(doc, method): @frappe.whitelist(allow_guest=True) -def sign_up(email, full_name, verify_terms, user_category): +def sign_up(email: str, full_name: str, verify_terms: bool, user_category: str): if is_signup_disabled(): frappe.throw(_("Sign Up is disabled"), _("Not Allowed")) @@ -75,7 +75,7 @@ def sign_up(email, full_name, verify_terms, user_category): return 2, _("Please ask your administrator to verify your sign-up") -def set_country_from_ip(login_manager=None, user=None): +def set_country_from_ip(login_manager: object = None, user: str = None): if not user and login_manager: user = login_manager.user user_country = frappe.db.get_value("User", user, "country") diff --git a/lms/lms/utils.py b/lms/lms/utils.py index f9c127c1..56ff7258 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -8,6 +8,7 @@ from frappe import _ from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_result from frappe.desk.doctype.notification_log.notification_log import make_notification_logs from frappe.desk.notifications import extract_mentions +from frappe.model.document import Document from frappe.rate_limiter import rate_limit from frappe.utils import ( add_months, @@ -44,11 +45,11 @@ def get_lms_route(path=""): return f"{base}/{path.lstrip('/')}" -def extend_bootinfo(bootinfo): +def extend_bootinfo(bootinfo: dict): bootinfo["lms_path"] = get_lms_path() -def slugify(title, used_slugs=None): +def slugify(title: str, used_slugs: list = None): """Converts title to a slug. If a list of used slugs is specified, it will make sure the generated slug @@ -78,13 +79,13 @@ def slugify(title, used_slugs=None): count = count + 1 -def generate_slug(title, doctype): +def generate_slug(title: str, doctype: str): result = frappe.get_all(doctype, fields=["name"]) slugs = {row["name"] for row in result} return slugify(title, used_slugs=slugs) -def get_membership(course, member=None): +def get_membership(course: str, member: str = None): if not member: member = frappe.session.user @@ -110,7 +111,7 @@ def get_membership(course, member=None): return False -def get_chapters(course): +def get_chapters(course: str): """Returns all chapters of this course.""" if not course: return [] @@ -126,7 +127,7 @@ def get_chapters(course): return chapters -def get_lessons(course, chapter=None, get_details=True, progress=False): +def get_lessons(course: str, chapter: str = None, get_details: bool = True, progress: bool = False): """If chapter is passed, returns lessons of only that chapter. Else returns lessons of all chapters of the course""" lessons = [] @@ -146,7 +147,7 @@ def get_lessons(course, chapter=None, get_details=True, progress=False): return lessons if get_details else lesson_count -def get_lesson_details(chapter, progress=False): +def get_lesson_details(chapter: dict, progress: bool = False): lessons = [] lesson_list = frappe.get_all( "Lesson Reference", {"parent": chapter.name}, ["lesson", "idx"], order_by="idx" @@ -182,7 +183,7 @@ def get_lesson_details(chapter, progress=False): return lessons -def get_lesson_icon(body, content): +def get_lesson_icon(body: str, content: str): if content: content = json.loads(content) @@ -222,7 +223,7 @@ def get_lesson_icon(body, content): return "icon-list" -def get_instructors(doctype, docname): +def get_instructors(doctype: str, docname: str): instructor_details = [] instructors = frappe.get_all( "Course Instructor", @@ -243,7 +244,7 @@ def get_instructors(doctype, docname): return instructor_details -def get_average_rating(course): +def get_average_rating(course: str): ratings = [review.rating for review in get_reviews(course)] if not len(ratings): return None @@ -252,7 +253,7 @@ def get_average_rating(course): @frappe.whitelist(allow_guest=True) @rate_limit(limit=500, seconds=60 * 60) -def get_reviews(course): +def get_reviews(course: str): reviews = frappe.get_all( "LMS Course Review", {"course": course}, @@ -274,7 +275,7 @@ def get_reviews(course): return reviews -def get_lesson_index(lesson_name): +def get_lesson_index(lesson_name: str) -> str: """Returns the {chapter_index}.{lesson_index} for the lesson.""" lesson = frappe.db.get_value("Lesson Reference", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True) if not lesson: @@ -287,13 +288,13 @@ def get_lesson_index(lesson_name): return f"{chapter.idx}-{lesson.idx}" -def get_lesson_url(course, lesson_number): +def get_lesson_url(course: str, lesson_number: str): if not lesson_number: return return get_lms_route(f"courses/{course}/learn/{lesson_number}") -def get_progress(course, lesson, member=None): +def get_progress(course: str, lesson: str, member: str = None): if not member: member = frappe.session.user @@ -304,7 +305,7 @@ def get_progress(course, lesson, member=None): ) -def get_course_progress(course, member=None): +def get_course_progress(course: str, member: str = None): """Returns the course progress of the session user""" lesson_count = get_lessons(course, get_details=False) if not lesson_count: @@ -317,7 +318,7 @@ def get_course_progress(course, member=None): return flt(((completed_lessons / lesson_count) * 100), precision) -def is_instructor(course): +def is_instructor(course: str) -> bool: instructors = get_instructors("LMS Course", course) for instructor in instructors: if instructor.name == frappe.session.user: @@ -325,7 +326,7 @@ def is_instructor(course): return False -def has_course_instructor_role(member=None): +def has_course_instructor_role(member: str = None): return frappe.db.get_value( "Has Role", {"parent": member or frappe.session.user, "role": "Course Creator"}, @@ -333,7 +334,7 @@ def has_course_instructor_role(member=None): ) -def has_moderator_role(member=None): +def has_moderator_role(member: str = None): return frappe.db.get_value( "Has Role", {"parent": member or frappe.session.user, "role": "Moderator"}, @@ -341,7 +342,7 @@ def has_moderator_role(member=None): ) -def has_evaluator_role(member=None): +def has_evaluator_role(member: str = None): return frappe.db.get_value( "Has Role", {"parent": member or frappe.session.user, "role": "Batch Evaluator"}, @@ -349,7 +350,7 @@ def has_evaluator_role(member=None): ) -def has_student_role(member=None): +def has_student_role(member: str = None): return frappe.db.get_value( "Has Role", {"parent": member or frappe.session.user, "role": "LMS Student"}, @@ -376,7 +377,7 @@ def get_courses_under_review(): ) -def validate_image(path): +def validate_image(path: str) -> str: if path and "/private" in path: frappe.db.set_value( "File", @@ -388,7 +389,7 @@ def validate_image(path): return path -def handle_notifications(doc, method): +def handle_notifications(doc: Document, method: str): topic = frappe.db.get_value( "Discussion Topic", doc.topic, @@ -402,7 +403,7 @@ def handle_notifications(doc, method): notify_mentions_via_email(doc, topic) -def get_course_details_for_notification(topic): +def get_course_details_for_notification(topic: dict): users = [] course = frappe.db.get_value("Course Lesson", topic.reference_docname, "course") course_title = frappe.db.get_value("LMS Course", course, "title") @@ -419,7 +420,7 @@ def get_course_details_for_notification(topic): return subject, link, users -def get_batch_details_for_notification(topic): +def get_batch_details_for_notification(topic: dict): users = [] batch_title = frappe.db.get_value("LMS Batch", topic.reference_docname, "title") subject = _("New comment in batch {0}").format(batch_title) @@ -435,7 +436,7 @@ def get_batch_details_for_notification(topic): return subject, link, users -def create_notification_log(doc, topic): +def create_notification_log(doc: Document, topic: dict): if topic.reference_doctype == "Course Lesson": subject, link, users = get_course_details_for_notification(topic) else: @@ -459,7 +460,7 @@ def create_notification_log(doc, topic): make_notification_logs(notification, users) -def notify_mentions_on_portal(doc, topic): +def notify_mentions_on_portal(doc: Document, topic: dict): mentions = extract_mentions(doc.reply) if not mentions: return @@ -495,7 +496,7 @@ def notify_mentions_on_portal(doc, topic): make_notification_logs(notification, user) -def notify_mentions_via_email(doc, topic): +def notify_mentions_via_email(doc: Document, topic: dict): outgoing_email_account = frappe.get_cached_value( "Email Account", {"default_outgoing": 1, "enable_outgoing": 1}, "name" ) @@ -542,7 +543,7 @@ def notify_mentions_via_email(doc, topic): ) -def get_lesson_count(course): +def get_lesson_count(course: str) -> int: lesson_count = 0 chapters = frappe.get_all("Chapter Reference", {"parent": course}, ["chapter"]) for chapter in chapters: @@ -554,10 +555,10 @@ def get_lesson_count(course): @frappe.whitelist(allow_guest=True) @rate_limit(limit=500, seconds=60 * 60) def get_chart_data( - chart_name, - timegrain="Daily", - from_date=None, - to_date=None, + chart_name: str, + timegrain: str = "Daily", + from_date: str = None, + to_date: str = None, ): from_date, to_date = get_chart_date_range(from_date, to_date) chart = frappe.get_doc("Dashboard Chart", chart_name) @@ -578,7 +579,7 @@ def get_chart_data( return data -def get_chart_date_range(from_date, to_date): +def get_chart_date_range(from_date: str, to_date: str): if not from_date: from_date = add_months(getdate(), -1) if not to_date: @@ -590,7 +591,7 @@ def get_chart_date_range(from_date, to_date): return from_date, to_date -def get_chart_filters(doctype, chart, datefield, from_date, to_date): +def get_chart_filters(doctype: str, chart: object, datefield: str, from_date: str, to_date: str): version = get_frappe_version() if version.startswith("15.") or version.startswith("14."): filters = [([chart.document_type, "docstatus", "<", 2, False])] @@ -606,7 +607,9 @@ def get_chart_filters(doctype, chart, datefield, from_date, to_date): return filters -def get_chart_details(doctype, datefield, value_field, chart, from_date, to_date): +def get_chart_details( + doctype: str, datefield: str, value_field: str, chart: object, from_date: str, to_date: str +): filters = get_chart_filters(doctype, chart, datefield, from_date, to_date) version = get_frappe_version() if version.startswith("15.") or version.startswith("14."): @@ -641,7 +644,7 @@ def get_course_completion_data(): ] -def get_evaluator(course, batch=None): +def get_evaluator(course: str, batch: str = None): evaluator = None if batch: evaluator = frappe.db.get_value( @@ -654,7 +657,7 @@ def get_evaluator(course, batch=None): return evaluator -def check_multicurrency(amount, currency, country=None, amount_usd=None): +def check_multicurrency(amount: float, currency: str, country: str = None, amount_usd: float = None): settings = frappe.get_single("LMS Settings") show_usd_equivalent = settings.show_usd_equivalent @@ -697,7 +700,7 @@ def check_multicurrency(amount, currency, country=None, amount_usd=None): return rounded(amount), currency -def apply_gst(amount, country=None): +def apply_gst(amount: float, country: str = None) -> tuple: gst_applied = 0 apply_gst = frappe.db.get_single_value("LMS Settings", "apply_gst") @@ -711,7 +714,7 @@ def apply_gst(amount, country=None): return amount, gst_applied -def get_current_exchange_rate(source, target="USD"): +def get_current_exchange_rate(source: str, target: str = "USD") -> float: url = f"https://api.frankfurter.app/latest?from={source}&to={target}" response = requests.request("GET", url) @@ -728,7 +731,7 @@ def guest_access_allowed(): @frappe.whitelist(allow_guest=True) @rate_limit(limit=500, seconds=60 * 60) -def get_courses(filters=None, start=0): +def get_courses(filters: dict = None, start: int = 0) -> list: """Returns the list of courses.""" if not guest_access_allowed(): @@ -758,7 +761,7 @@ def get_courses(filters=None, start=0): return courses -def get_course_card_details(courses): +def get_course_card_details(courses: list) -> list: for course in courses: course.instructors = get_instructors("LMS Course", course.name) @@ -771,7 +774,7 @@ def get_course_card_details(courses): return courses -def get_course_or_filters(filters): +def get_course_or_filters(filters: dict) -> dict: or_filters = {} or_filters.update({"title": filters.get("title")}) or_filters.update({"short_introduction": filters.get("title")}) @@ -780,7 +783,7 @@ def get_course_or_filters(filters): return or_filters -def update_course_filters(filters): +def update_course_filters(filters: dict) -> tuple: or_filters = {} show_featured = False @@ -813,7 +816,7 @@ def update_course_filters(filters): return filters, or_filters, show_featured -def get_enrollment_details(courses): +def get_enrollment_details(courses: list) -> list: for course in courses: filters = { "course": course.name, @@ -831,7 +834,7 @@ def get_enrollment_details(courses): return courses -def get_featured_courses(filters, or_filters, fields): +def get_featured_courses(filters: dict, or_filters: dict, fields: list) -> list: filters.update({"featured": 1}) featured_courses = frappe.get_all( "LMS Course", @@ -874,12 +877,13 @@ def get_course_fields(): @frappe.whitelist(allow_guest=True) @rate_limit(limit=500, seconds=60 * 60) -def get_course_details(course): +def get_course_details(course: str): if not guest_access_allowed(): return {} is_course_published = frappe.db.get_value("LMS Course", course, "published") - if not is_course_published and not can_modify_course(course): + membership = get_membership(course) + if not is_course_published and not can_modify_course(course) and not membership: return {} fields = get_course_fields() @@ -891,6 +895,7 @@ def get_course_details(course): ) course_details.instructors = get_instructors("LMS Course", course_details.name) + course_details.membership = membership # course_details.is_instructor = is_instructor(course_details.name) if course_details.paid_course or course_details.paid_certificate: """course_details.course_price, course_details.currency = check_multicurrency( @@ -899,15 +904,7 @@ def get_course_details(course): course_details.price = fmt_money(course_details.course_price, 0, course_details.currency) if frappe.session.user == "Guest": - course_details.membership = None course_details.is_instructor = False - else: - course_details.membership = frappe.db.get_value( - "LMS Enrollment", - {"member": frappe.session.user, "course": course_details.name}, - ["name", "course", "current_lesson", "progress", "member"], - as_dict=1, - ) if course_details.membership and course_details.membership.current_lesson: course_details.current_lesson = get_lesson_index(course_details.membership.current_lesson) @@ -915,7 +912,7 @@ def get_course_details(course): return course_details -def get_categorized_courses(courses): +def get_categorized_courses(courses: list) -> dict: live, upcoming, new, enrolled, created, under_review = [], [], [], [], [], [] for course in courses: @@ -951,7 +948,7 @@ def get_categorized_courses(courses): @frappe.whitelist(allow_guest=True) -def get_course_outline(course, progress=False): +def get_course_outline(course: str, progress: bool = False) -> list: """Returns the course outline.""" if not guest_access_allowed(): @@ -983,7 +980,7 @@ def get_course_outline(course, progress=False): @frappe.whitelist(allow_guest=True) @rate_limit(limit=500, seconds=60 * 60) -def get_lesson(course, chapter, lesson): +def get_lesson(course: str, chapter: int, lesson: int) -> dict: if not guest_access_allowed(): return {} @@ -1013,12 +1010,7 @@ def get_lesson(course, chapter, lesson): as_dict=1, ) - if ( - not lesson_details.include_in_preview - and not membership - and not has_moderator_role() - and not is_instructor(course) - ): + if not lesson_details.include_in_preview and not membership and not can_modify_course(course): return { "no_preview": 1, "title": lesson_details.title, @@ -1067,7 +1059,7 @@ def get_lesson(course, chapter, lesson): return lesson_details -def get_video_details(lesson_name): +def get_video_details(lesson_name: str) -> list: return frappe.get_all( "LMS Video Watch Duration", {"lesson": lesson_name, "member": frappe.session.user}, @@ -1075,7 +1067,7 @@ def get_video_details(lesson_name): ) -def get_neighbour_lesson(course, chapter, lesson): +def get_neighbour_lesson(course: str, chapter: int, lesson: int) -> dict: numbers = [] current = f"{chapter}.{lesson}" chapters = frappe.get_all("Chapter Reference", {"parent": course}, ["idx", "chapter"]) @@ -1097,7 +1089,7 @@ def get_neighbour_lesson(course, chapter, lesson): @frappe.whitelist(allow_guest=True) @rate_limit(limit=500, seconds=60 * 60) -def get_batch_details(batch): +def get_batch_details(batch: str): if not guest_access_allowed(): return {} @@ -1168,7 +1160,7 @@ def get_batch_details(batch): return batch_details -def categorize_batches(batches): +def categorize_batches(batches: list) -> dict: upcoming, archived, private, enrolled = [], [], [], [] for batch in batches: @@ -1212,7 +1204,7 @@ def get_country_code(): @frappe.whitelist() -def get_question_details(question): +def get_question_details(question: str) -> dict: fields = ["question", "type", "multiple"] for i in range(1, 5): fields.append(f"option_{i}") @@ -1224,7 +1216,7 @@ def get_question_details(question): @frappe.whitelist(allow_guest=True) @rate_limit(limit=500, seconds=60 * 60) -def get_batch_courses(batch): +def get_batch_courses(batch: str) -> list: if not guest_access_allowed(): return [] @@ -1233,14 +1225,15 @@ def get_batch_courses(batch): for course in course_list: details = get_course_details(course.course) - details.batch_course = course.name - courses.append(details) + if details.get("name"): + details.batch_course = course.name + courses.append(details) return courses @frappe.whitelist() -def get_assessments(batch): +def get_assessments(batch: str) -> list: member = frappe.session.user assessments = frappe.get_all( "LMS Assessment", @@ -1262,7 +1255,7 @@ def get_assessments(batch): return assessments -def get_assignment_details(assessment, member): +def get_assignment_details(assessment: dict, member: str) -> dict: assessment.title = frappe.db.get_value("LMS Assignment", assessment.assessment_name, "title") existing_submission = frappe.db.exists( @@ -1293,7 +1286,7 @@ def get_assignment_details(assessment, member): return assessment -def get_quiz_details(assessment, member): +def get_quiz_details(assessment: dict, member: str) -> dict: assessment_details = frappe.db.get_value( "LMS Quiz", assessment.assessment_name, ["title", "passing_percentage"], as_dict=1 ) @@ -1325,7 +1318,7 @@ def get_quiz_details(assessment, member): return assessment -def get_exercise_details(assessment, member): +def get_exercise_details(assessment: dict, member: str) -> dict: assessment.title = frappe.db.get_value("LMS Programming Exercise", assessment.assessment_name, "title") filters = {"member": member, "exercise": assessment.assessment_name} @@ -1349,7 +1342,7 @@ def get_exercise_details(assessment, member): @frappe.whitelist() -def get_batch_assessment_count(batch): +def get_batch_assessment_count(batch: str) -> int: frappe.only_for(["Moderator", "Batch Evaluator"]) if not frappe.db.exists("LMS Batch", batch): frappe.throw(_("The specified batch does not exist.")) @@ -1357,7 +1350,9 @@ def get_batch_assessment_count(batch): @frappe.whitelist() -def get_batch_students(filters, offset=0, limit_start=0, limit_page_length=None, limit=None): +def get_batch_students( + filters: dict, offset: int = 0, limit_start: int = 0, limit_page_length: int = None, limit: int = None +): # limit_start and limit_page_length are used for backward compatibility start = limit_start or offset page_length = limit_page_length or limit @@ -1386,7 +1381,7 @@ def get_batch_students(filters, offset=0, limit_start=0, limit_page_length=None, return students -def get_course_completion_stats(batch): +def get_course_completion_stats(batch: str) -> list: """Get completion counts per course in batch""" BatchCourse = frappe.qb.DocType("Batch Course") BatchEnrollment = frappe.qb.DocType("LMS Batch Enrollment") @@ -1409,7 +1404,7 @@ def get_course_completion_stats(batch): return [{"task": row.title, "value": row.completed or 0} for row in rows] -def get_assignment_pass_stats(batch): +def get_assignment_pass_stats(batch: str) -> list: """Get pass counts per assignment in batch""" Assessment = frappe.qb.DocType("LMS Assessment") Assignment = frappe.qb.DocType("LMS Assignment") @@ -1438,7 +1433,7 @@ def get_assignment_pass_stats(batch): return [{"task": row.title, "value": row.passed or 0} for row in rows] -def get_quiz_pass_stats(batch): +def get_quiz_pass_stats(batch: str) -> list: """Get pass counts per quiz in batch""" Assessment = frappe.qb.DocType("LMS Assessment") Quiz = frappe.qb.DocType("LMS Quiz") @@ -1467,7 +1462,7 @@ def get_quiz_pass_stats(batch): @frappe.whitelist() -def get_batch_chart_data(batch): +def get_batch_chart_data(batch: str) -> list: """Get completion counts per course and assessment""" if not can_modify_batch(batch): frappe.throw(_("You are not authorized to view the chart data of this batch.")) @@ -1477,7 +1472,7 @@ def get_batch_chart_data(batch): return get_course_completion_stats(batch) + get_assignment_pass_stats(batch) + get_quiz_pass_stats(batch) -def get_batch_student_details(student): +def get_batch_student_details(student: dict) -> dict: details = frappe.db.get_value( "User", student.member, @@ -1490,7 +1485,7 @@ def get_batch_student_details(student): return details -def calculate_student_progress(batch, details): +def calculate_student_progress(batch: str, details: dict): batch_courses = frappe.get_all("Batch Course", {"parent": batch}, ["course", "title"]) assessments = frappe.get_all( "LMS Assessment", @@ -1514,7 +1509,7 @@ def calculate_student_progress(batch, details): details.progress = 0 -def calculate_course_progress(batch_courses, details): +def calculate_course_progress(batch_courses: list, details: dict): course_progress = [] details.courses = frappe._dict() @@ -1533,7 +1528,7 @@ def calculate_course_progress(batch_courses, details): ) -def calculate_assessment_progress(assessments, details): +def calculate_assessment_progress(assessments: list, details: dict): assessments_completed = 0 details.assessments = frappe._dict() @@ -1552,7 +1547,7 @@ def calculate_assessment_progress(assessments, details): ) -def has_submitted_assessment(assessment, assessment_type, member=None): +def has_submitted_assessment(assessment: str, assessment_type: str, member: str = None): if not member: member = frappe.session.user @@ -1607,7 +1602,7 @@ def has_submitted_assessment(assessment, assessment_type, member=None): ) -def can_access_topic(doctype, docname): +def can_access_topic(doctype: str, docname: str) -> bool: is_student = False if doctype == "Course Lesson": course = frappe.db.get_value("Course Lesson", docname, "course") @@ -1624,7 +1619,7 @@ def can_access_topic(doctype, docname): @frappe.whitelist() -def get_discussion_topics(doctype, docname, single_thread): +def get_discussion_topics(doctype: str, docname: str, single_thread: bool = False): if not can_access_topic(doctype, docname): frappe.throw(_("You are not authorized to view the discussion topics for this item.")) @@ -1654,7 +1649,7 @@ def get_discussion_topics(doctype, docname, single_thread): return topics -def create_discussion_topic(doctype, docname): +def create_discussion_topic(doctype: str, docname: str) -> str: doc = frappe.new_doc("Discussion Topic") doc.update( { @@ -1668,9 +1663,11 @@ def create_discussion_topic(doctype, docname): @frappe.whitelist() -def get_discussion_replies(topic): - doctype = frappe.db.get_value("Discussion Topic", topic, "reference_doctype") - if not can_access_topic(doctype, topic): +def get_discussion_replies(topic: str): + topic_details = frappe.db.get_value( + "Discussion Topic", topic, ["reference_doctype", "reference_docname"], as_dict=1 + ) + if not can_access_topic(topic_details.reference_doctype, topic_details.reference_docname): frappe.throw(_("You are not authorized to view the discussion replies for this topic.")) replies = frappe.get_all( @@ -1689,7 +1686,7 @@ def get_discussion_replies(topic): @frappe.whitelist() -def get_order_summary(doctype, docname, coupon=None, country=None): +def get_order_summary(doctype: str, docname: str, coupon: str = None, country: str = None): details = get_paid_course_details(docname) if doctype == "LMS Course" else get_paid_batch_details(docname) details.amount, details.currency = check_multicurrency( @@ -1708,7 +1705,7 @@ def get_order_summary(doctype, docname, coupon=None, country=None): return details -def get_paid_course_details(docname): +def get_paid_course_details(docname: str) -> dict: details = frappe.db.get_value( "LMS Course", docname, @@ -1730,7 +1727,7 @@ def get_paid_course_details(docname): return details -def get_paid_batch_details(docname): +def get_paid_batch_details(docname: str) -> dict: details = frappe.db.get_value( "LMS Batch", docname, @@ -1744,7 +1741,7 @@ def get_paid_batch_details(docname): return details -def adjust_amount_for_coupon(details, coupon, doctype, docname): +def adjust_amount_for_coupon(details: dict, coupon: str, doctype: str, docname: str): if not coupon: return discount_amount, subtotal, coupon_name = apply_coupon(doctype, docname, coupon, details.amount) @@ -1754,7 +1751,7 @@ def adjust_amount_for_coupon(details, coupon, doctype, docname): details.coupon = coupon_name -def get_gst_details(details, country): +def get_gst_details(details: dict, country: str): if details.currency != "INR": return @@ -1762,7 +1759,7 @@ def get_gst_details(details, country): details.gst_amount_formatted = fmt_money(details.gst_applied, 0, details.currency) -def apply_coupon(doctype, docname, code, base_amount): +def apply_coupon(doctype: str, docname: str, code: str, base_amount: float): coupon_name = frappe.db.exists("LMS Coupon", {"code": code, "enabled": 1}) if not coupon_name: frappe.throw(_("The coupon code '{0}' is invalid.").format(code)) @@ -1792,7 +1789,7 @@ def apply_coupon(doctype, docname, code, base_amount): return discount_amount, subtotal, coupon_name -def validate_coupon(code, coupon): +def validate_coupon(code: str, coupon: dict): if coupon.expires_on and getdate(coupon.expires_on) < getdate(): frappe.throw(_("This coupon has expired.")) @@ -1800,7 +1797,7 @@ def validate_coupon(code, coupon): frappe.throw(_("This coupon has reached its maximum usage limit.")) -def validate_coupon_applicability(doctype, docname, coupon_name): +def validate_coupon_applicability(doctype: str, docname: str, coupon_name: str): applicable_item = frappe.db.exists( "LMS Coupon Item", {"parent": coupon_name, "reference_doctype": doctype, "reference_name": docname} ) @@ -1812,7 +1809,7 @@ def validate_coupon_applicability(doctype, docname, coupon_name): ) -def calculate_discount_amount(base_amount, coupon): +def calculate_discount_amount(base_amount: float, coupon: dict) -> float: discount_amount = 0 if coupon.discount_type == "Percentage": @@ -1824,7 +1821,7 @@ def calculate_discount_amount(base_amount, coupon): @frappe.whitelist() -def get_lesson_creation_details(course, chapter, lesson): +def get_lesson_creation_details(course: str, chapter: int, lesson: int) -> dict: frappe.only_for(["Moderator", "Course Creator"]) chapter_name = frappe.db.get_value("Chapter Reference", {"parent": course, "idx": chapter}, "chapter") lesson_name = frappe.db.get_value("Lesson Reference", {"parent": chapter_name, "idx": lesson}, "lesson") @@ -1855,7 +1852,7 @@ def get_lesson_creation_details(course, chapter, lesson): @frappe.whitelist() -def get_roles(name): +def get_roles(name: str) -> dict: frappe.only_for(["Moderator", "Batch Evaluator"]) return { "moderator": has_moderator_role(name), @@ -1865,11 +1862,11 @@ def get_roles(name): } -def publish_notifications(doc, method): +def publish_notifications(doc: Document, method: str): frappe.publish_realtime("publish_lms_notifications", user=doc.for_user, after_commit=True) -def update_payment_record(doctype, docname): +def update_payment_record(doctype: str, docname: str): request = get_integration_requests(doctype, docname) if len(request): @@ -1888,7 +1885,7 @@ def update_payment_record(doctype, docname): enroll_in_batch(docname, data.payment) -def get_integration_requests(doctype, docname): +def get_integration_requests(doctype: str, docname: str): return frappe.get_all( "Integration Request", { @@ -1902,13 +1899,13 @@ def get_integration_requests(doctype, docname): ) -def get_payment_doc(payment_name): +def get_payment_doc(payment_name: str) -> dict: return frappe.db.get_value( "LMS Payment", payment_name, ["name", "coupon", "payment_for_certificate"], as_dict=True ) -def update_payment_details(data): +def update_payment_details(data: dict): payment_id = get_payment_id(data) frappe.db.set_value( @@ -1922,7 +1919,7 @@ def update_payment_details(data): ) -def get_payment_id(data): +def get_payment_id(data: dict) -> str: payment_gateway = data.get("payment_gateway") if payment_gateway == "Razorpay": payment_id = "razorpay_payment_id" @@ -1933,7 +1930,7 @@ def get_payment_id(data): return payment_id -def update_coupon_redemption(payment_doc): +def update_coupon_redemption(payment_doc: dict): if payment_doc.coupon: redemption_count = frappe.db.get_value("LMS Coupon", payment_doc.coupon, "redemption_count") or 0 @@ -1945,7 +1942,7 @@ def update_coupon_redemption(payment_doc): ) -def enroll_in_course(course, payment_name): +def enroll_in_course(course: str, payment_name: str): if not frappe.db.exists("LMS Enrollment", {"member": frappe.session.user, "course": course}): enrollment = frappe.new_doc("LMS Enrollment") payment = frappe.db.get_value("LMS Payment", payment_name, ["name", "source"], as_dict=True) @@ -1961,7 +1958,7 @@ def enroll_in_course(course, payment_name): @frappe.whitelist() -def enroll_in_batch(batch, payment_name=None): +def enroll_in_batch(batch: str, payment_name: str = None): if not frappe.db.exists("LMS Batch", batch): frappe.throw(_("The specified batch does not exist.")) @@ -1969,7 +1966,7 @@ def enroll_in_batch(batch, payment_name=None): create_enrollment(batch, payment_doc) -def get_payment_details(payment_name): +def get_payment_details(payment_name: str) -> dict: payment_doc = None if payment_name: payment_doc = frappe.db.get_value( @@ -1978,7 +1975,7 @@ def get_payment_details(payment_name): return payment_doc -def create_enrollment(batch, payment_doc=None): +def create_enrollment(batch: str, payment_doc: dict = None): new_student = frappe.new_doc("LMS Batch Enrollment") new_student.update( { @@ -1997,7 +1994,7 @@ def create_enrollment(batch, payment_doc=None): new_student.save() -def update_certificate_purchase(course, payment_name): +def update_certificate_purchase(course: str, payment_name: str): frappe.db.set_value( "LMS Enrollment", {"member": frappe.session.user, "course": course}, @@ -2044,10 +2041,17 @@ def get_programs(): @frappe.whitelist() -def get_program_details(program_name): +def get_program_details(program_name: str) -> dict: if not guest_access_allowed(): frappe.throw(_("Please login to view program details.")) + is_published = frappe.db.get_value("LMS Program", program_name, "published") + is_member = frappe.db.exists( + "LMS Program Member", {"parent": program_name, "member": frappe.session.user} + ) + if not is_published and not is_member: + frappe.throw(_("You are not authorized to view the details of this program.")) + program = frappe.db.get_value( "LMS Program", program_name, @@ -2088,7 +2092,7 @@ def get_program_details(program_name): @frappe.whitelist() -def enroll_in_program(program): +def enroll_in_program(program: str): validate_program_enrollment(program) if not frappe.db.exists("LMS Program Member", {"parent": program, "member": frappe.session.user}): @@ -2104,7 +2108,7 @@ def enroll_in_program(program): program_member.save(ignore_permissions=True) -def validate_program_enrollment(program): +def validate_program_enrollment(program: str): published = frappe.db.get_value("LMS Program", program, "published") if not published: frappe.throw(_("You cannot enroll in an unpublished program.")) @@ -2112,7 +2116,7 @@ def validate_program_enrollment(program): @frappe.whitelist(allow_guest=True) @rate_limit(limit=500, seconds=60 * 60) -def get_batches(filters=None, start=0, order_by="start_date"): +def get_batches(filters: dict = None, start: int = 0, order_by: str = "start_date"): if not guest_access_allowed(): return [] @@ -2156,7 +2160,7 @@ def get_batches(filters=None, start=0, order_by="start_date"): return batches -def filter_batches_based_on_start_time(batches, filters): +def filter_batches_based_on_start_time(batches: list, filters: dict) -> list: batchType = get_batch_type(filters) if batchType == "upcoming": batches_to_remove = [ @@ -2175,7 +2179,7 @@ def filter_batches_based_on_start_time(batches, filters): return batches -def get_batch_type(filters): +def get_batch_type(filters: dict) -> str: start_date_filter = filters.get("start_date") batchType = None if start_date_filter: @@ -2188,7 +2192,7 @@ def get_batch_type(filters): return batchType -def get_batch_card_details(batches): +def get_batch_card_details(batches: list) -> list: for batch in batches: batch.instructors = get_instructors("LMS Batch", batch.name) students_count = frappe.db.count("LMS Batch Enrollment", {"batch": batch.name}) @@ -2205,7 +2209,7 @@ def get_batch_card_details(batches): return batches -def get_palette(full_name): +def get_palette(full_name: str) -> list: """ Returns a color unique to each member for Avatar""" @@ -2229,7 +2233,7 @@ def get_palette(full_name): @frappe.whitelist(allow_guest=True) @rate_limit(limit=500, seconds=60 * 60) -def get_related_courses(course): +def get_related_courses(course: str) -> list: if not guest_access_allowed(): return [] @@ -2245,7 +2249,7 @@ def persona_captured(): frappe.db.set_single_value("LMS Settings", "persona_captured", 1) -def validate_discussion_reply(doc, method): +def validate_discussion_reply(doc: Document, method: str): topic = frappe.db.get_value( "Discussion Topic", doc.topic, ["reference_doctype", "reference_docname"], as_dict=True ) @@ -2257,7 +2261,7 @@ def validate_discussion_reply(doc, method): validate_batch_access(topic.reference_docname) -def validate_course_access(lesson): +def validate_course_access(lesson: str): if not frappe.db.exists("Course Lesson", lesson): frappe.throw(_("The lesson does not exist.")) @@ -2273,7 +2277,7 @@ def validate_course_access(lesson): frappe.throw(_("You do not have access to this course.")) -def validate_batch_access(batch): +def validate_batch_access(batch: str): if not frappe.db.exists("LMS Batch", batch): frappe.throw(_("The batch does not exist.")) @@ -2290,7 +2294,7 @@ def validate_batch_access(batch): frappe.throw(_("You do not have access to this batch.")) -def can_modify_course(course): +def can_modify_course(course: str) -> bool: is_instructor = frappe.db.exists( "Course Instructor", {"instructor": frappe.session.user, "parent": course, "parenttype": "LMS Course"}, @@ -2300,7 +2304,7 @@ def can_modify_course(course): return True -def can_modify_batch(batch): +def can_modify_batch(batch: str) -> bool: is_instructor = frappe.db.exists( "Course Instructor", { diff --git a/lms/locale/es.po b/lms/locale/es.po index 391ea4e7..05f5a5c8 100644 --- a/lms/locale/es.po +++ b/lms/locale/es.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n" "POT-Creation-Date: 2026-01-23 16:05+0000\n" -"PO-Revision-Date: 2026-02-05 06:43\n" +"PO-Revision-Date: 2026-02-12 13:58\n" "Last-Translator: jannat@frappe.io\n" "Language-Team: Spanish\n" "MIME-Version: 1.0\n" @@ -2291,7 +2291,7 @@ msgstr "Detalles de la educación" #: lms/lms/doctype/lms_settings/lms_settings.json #: lms/templates/signup-form.html:10 msgid "Email" -msgstr "" +msgstr "Correo electrónico" #: frontend/src/components/Modals/Event.vue:16 msgid "Email ID" @@ -2850,7 +2850,7 @@ msgstr "Francés (por ejemplo, Distinción)" #: lms/lms/doctype/evaluator_schedule/evaluator_schedule.json #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json msgid "Friday" -msgstr "" +msgstr "Viernes" #. Label of the unavailable_from (Date) field in DocType 'Course Evaluator' #: frontend/src/pages/ProfileEvaluator.vue:106 @@ -4380,7 +4380,7 @@ msgstr "Módulo incorrecto." #: lms/lms/doctype/evaluator_schedule/evaluator_schedule.json #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json msgid "Monday" -msgstr "" +msgstr "Lunes" #: frontend/src/components/Sidebar/AppSidebar.vue:561 msgid "Monetization" @@ -5914,7 +5914,7 @@ msgstr "" #: lms/lms/doctype/evaluator_schedule/evaluator_schedule.json #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json msgid "Saturday" -msgstr "" +msgstr "Sábado" #. Button label of the job-opportunity Web Form #: frontend/src/components/AssessmentPlugin.vue:12 @@ -5983,7 +5983,7 @@ msgstr "Puntuación fuera de" #: frontend/src/pages/Jobs.vue:57 frontend/src/pages/Search/Search.vue:5 #: frontend/src/pages/Search/Search.vue:250 msgid "Search" -msgstr "" +msgstr "Buscar" #: frontend/src/components/Modals/CourseProgressSummary.vue:17 #: frontend/src/components/Modals/VideoStatistics.vue:20 @@ -6480,7 +6480,7 @@ msgstr "Resumen" #: lms/lms/doctype/evaluator_schedule/evaluator_schedule.json #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json msgid "Sunday" -msgstr "" +msgstr "Domingo" #: lms/lms/api.py:995 msgid "Suspicious pattern found in {0}: {1}" @@ -6536,7 +6536,7 @@ msgstr "" #: lms/lms/doctype/user_skill/user_skill.json #: lms/lms/doctype/zoom_settings/zoom_settings.json msgid "System Manager" -msgstr "" +msgstr "Administrador del sistema" #. Label of the tags (Data) field in DocType 'LMS Course' #: frontend/src/pages/CourseForm.vue:51 @@ -6791,7 +6791,7 @@ msgstr "" #: lms/lms/doctype/evaluator_schedule/evaluator_schedule.json #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json msgid "Thursday" -msgstr "" +msgstr "Jueves" #. Label of the time (Time) field in DocType 'LMS Live Class' #: frontend/src/components/Modals/Event.vue:54 @@ -6974,7 +6974,7 @@ msgstr "Inténtelo de nuevo" #: lms/lms/doctype/evaluator_schedule/evaluator_schedule.json #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json msgid "Tuesday" -msgstr "" +msgstr "Martes" #: frontend/src/pages/ProfileAbout.vue:105 msgid "Twitter" @@ -7287,7 +7287,7 @@ msgstr "" #: lms/lms/doctype/evaluator_schedule/evaluator_schedule.json #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json msgid "Wednesday" -msgstr "" +msgstr "Miércoles" #: lms/templates/emails/lms_invite_request_approved.html:4 msgid "Welcome to {0}!" diff --git a/lms/locale/fa.po b/lms/locale/fa.po index 902d7606..232d4265 100644 --- a/lms/locale/fa.po +++ b/lms/locale/fa.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n" "POT-Creation-Date: 2026-01-23 16:05+0000\n" -"PO-Revision-Date: 2026-02-05 06:43\n" +"PO-Revision-Date: 2026-02-15 14:24\n" "Last-Translator: jannat@frappe.io\n" "Language-Team: Persian\n" "MIME-Version: 1.0\n" @@ -985,7 +985,7 @@ msgstr "" #: lms/lms/doctype/lms_category/lms_category.json #: lms/lms/doctype/lms_course/lms_course.json lms/templates/signup-form.html:22 msgid "Category" -msgstr "دسته بندی" +msgstr "دسته‌بندی" #: frontend/src/components/Settings/Categories.vue:39 msgid "Category Name" diff --git a/lms/locale/it.po b/lms/locale/it.po index b052da81..d6656e2d 100644 --- a/lms/locale/it.po +++ b/lms/locale/it.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n" "POT-Creation-Date: 2026-01-23 16:05+0000\n" -"PO-Revision-Date: 2026-02-05 06:43\n" +"PO-Revision-Date: 2026-02-10 12:02\n" "Last-Translator: jannat@frappe.io\n" "Language-Team: Italian\n" "MIME-Version: 1.0\n" @@ -1324,7 +1324,7 @@ msgstr "" #: lms/job/doctype/lms_job_application/lms_job_application.json #: lms/lms/doctype/work_experience/work_experience.json msgid "Company" -msgstr "" +msgstr "Azienda" #. Label of the section_break_6 (Section Break) field in DocType 'Job #. Opportunity' @@ -2291,7 +2291,7 @@ msgstr "" #: lms/lms/doctype/lms_settings/lms_settings.json #: lms/templates/signup-form.html:10 msgid "Email" -msgstr "E-mail" +msgstr "Email" #: frontend/src/components/Modals/Event.vue:16 msgid "Email ID" diff --git a/lms/locale/my.po b/lms/locale/my.po index 062c1a32..4776bd2c 100644 --- a/lms/locale/my.po +++ b/lms/locale/my.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n" "POT-Creation-Date: 2026-01-23 16:05+0000\n" -"PO-Revision-Date: 2026-02-05 06:43\n" +"PO-Revision-Date: 2026-02-11 13:22\n" "Last-Translator: jannat@frappe.io\n" "Language-Team: Burmese\n" "MIME-Version: 1.0\n" @@ -962,7 +962,7 @@ msgstr "" #. Option for the 'Status' (Select) field in DocType 'LMS Certificate Request' #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json msgid "Cancelled" -msgstr "" +msgstr "ပယ်ဖျက်ခဲ့သည်။" #. Label of the carrer_preference_details (Section Break) field in DocType #. 'User' @@ -5942,7 +5942,7 @@ msgstr "" #: frontend/src/pages/Quizzes.vue:105 #: lms/job/web_form/job_opportunity/job_opportunity.json msgid "Save" -msgstr "" +msgstr "သိမ်းမည်။" #. Label of the schedule (Table) field in DocType 'Course Evaluator' #: lms/lms/doctype/course_evaluator/course_evaluator.json diff --git a/lms/locale/pt.po b/lms/locale/pt.po index 65b5c0a3..bf802c02 100644 --- a/lms/locale/pt.po +++ b/lms/locale/pt.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n" "POT-Creation-Date: 2026-01-23 16:05+0000\n" -"PO-Revision-Date: 2026-02-05 06:43\n" +"PO-Revision-Date: 2026-02-15 14:24\n" "Last-Translator: jannat@frappe.io\n" "Language-Team: Portuguese\n" "MIME-Version: 1.0\n" @@ -190,7 +190,7 @@ msgstr "" #: frontend/src/components/Controls/ChildTable.vue:77 #: frontend/src/components/Settings/Coupons/CouponItems.vue:55 msgid "Add Row" -msgstr "" +msgstr "Adicionar Linha" #: frontend/src/pages/ProfileEvaluator.vue:96 msgid "Add Slot" diff --git a/lms/locale/pt_BR.po b/lms/locale/pt_BR.po index 5665c7e6..85072e96 100644 --- a/lms/locale/pt_BR.po +++ b/lms/locale/pt_BR.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n" "POT-Creation-Date: 2026-01-23 16:05+0000\n" -"PO-Revision-Date: 2026-02-05 06:43\n" +"PO-Revision-Date: 2026-02-14 14:28\n" "Last-Translator: jannat@frappe.io\n" "Language-Team: Portuguese, Brazilian\n" "MIME-Version: 1.0\n" @@ -7831,7 +7831,7 @@ msgstr "" #: frontend/src/components/StudentHeatmap.vue:10 msgid "weeks" -msgstr "" +msgstr "semanas" #: lms/templates/emails/mentor_request_creation_email.html:5 msgid "you can" diff --git a/lms/patches.txt b/lms/patches.txt index fc7b88e4..e6a6e90d 100644 --- a/lms/patches.txt +++ b/lms/patches.txt @@ -115,4 +115,6 @@ lms.patches.v2_0.fix_scorm_lesson_reference_idx #02-09-2025 lms.patches.v2_0.certified_members_to_certifications #05-10-2025 lms.patches.v2_0.fix_job_application_resume_urls lms.patches.v2_0.open_to_opportunities -lms.patches.v2_0.open_to_work \ No newline at end of file +lms.patches.v2_0.open_to_work +lms.patches.v2_0.share_enrollment +lms.patches.v2_0.give_user_list_permission #11-02-2026 \ No newline at end of file diff --git a/lms/patches/v2_0/give_user_list_permission.py b/lms/patches/v2_0/give_user_list_permission.py new file mode 100644 index 00000000..be1d753f --- /dev/null +++ b/lms/patches/v2_0/give_user_list_permission.py @@ -0,0 +1,5 @@ +from lms.install import give_user_list_permission + + +def execute(): + give_user_list_permission() diff --git a/lms/patches/v2_0/share_enrollment.py b/lms/patches/v2_0/share_enrollment.py new file mode 100644 index 00000000..4834cbef --- /dev/null +++ b/lms/patches/v2_0/share_enrollment.py @@ -0,0 +1,20 @@ +import frappe + + +def execute(): + enrollments = frappe.get_all("LMS Enrollment", ["name", "member", "owner"]) + + for enrollment in enrollments: + if enrollment.owner == enrollment.member: + continue + filters = { + "user": enrollment.member, + "share_doctype": "LMS Enrollment", + "share_name": enrollment.name, + } + is_shared = frappe.db.exists("DocShare", filters) + if not is_shared: + share = frappe.new_doc("DocShare") + filters.update({"read": 1, "write": 1, "notify_by_email": 0}) + share.update(filters) + share.save() diff --git a/pyproject.toml b/pyproject.toml index 1463f1bc..4730269f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,4 +66,9 @@ indent-style = "tab" docstring-code-format = true [tool.bench.frappe-dependencies] -frappe = ">=15.0.0,<=17.0.0-dev" \ No newline at end of file +frappe = ">=15.0.0,<=17.0.0-dev" + +[tool.bench.assets] +build_dir = "./frontend" +out_dir = "../lms/public/frontend" +index_html_path = "../lms/www/_lms.html"