diff --git a/docker-compose.yml b/docker-compose.yml index fcc611ae..d7d7daa5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.5' - services: reverse-proxy: image: traefik diff --git a/frontend/Dockerfile b/frontend/Dockerfile index c9dcdc6a..006f8948 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,5 +1,5 @@ # Local development stage -FROM node:20.8-alpine3.18 as development-stage +FROM node:20.8-alpine3.18 AS development-stage WORKDIR /app COPY package.json /app/ COPY yarn.lock /app/ @@ -10,7 +10,7 @@ EXPOSE 3000 ENTRYPOINT ["yarn", "dev:host"] # Production Build stage -FROM node:20.8-alpine3.18 as production-build +FROM node:20.8-alpine3.18 AS production-build WORKDIR /app COPY ./src /app/src/ COPY package.json /app/ @@ -21,9 +21,9 @@ ARG VERSION_BUILD_TAG=latest ENV VITE_ROSALUTION_VERSION=$VERSION_BUILD_TAG -RUN yarn install --frozen-lockfile && yarn build --base=/rosalution/ +RUN yarn install --frozen-lockfile && yarn build --bASe=/rosalution/ -FROM nginx:1.25.2-alpine3.18 as production-stage +FROM nginx:1.25.2-alpine3.18 AS production-stage COPY etc/default.conf /etc/nginx/conf.d/ COPY --from=production-build /app/dist/ /usr/share/nginx/html/ diff --git a/frontend/package.json b/frontend/package.json index 1d416a93..9be7f56a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,7 +21,7 @@ "@fortawesome/free-solid-svg-icons": "6.4.2", "@fortawesome/vue-fontawesome": "3.0.3", "@rollup/plugin-strip": "3.0.4", - "vue": "3.3.4", + "vue": "3.5.12", "vue-router": "4.2.5" }, "devDependencies": { diff --git a/frontend/src/components/Dialogs/RosalutionToast.vue b/frontend/src/components/Dialogs/RosalutionToast.vue new file mode 100644 index 00000000..9ec327e8 --- /dev/null +++ b/frontend/src/components/Dialogs/RosalutionToast.vue @@ -0,0 +1,202 @@ + + + + + + + {{title}} + + + {{ state.message }} + + + + + + + + + + diff --git a/frontend/src/components/Dialogs/Toast.vue b/frontend/src/components/Dialogs/Toast.vue deleted file mode 100644 index 9beb944f..00000000 --- a/frontend/src/components/Dialogs/Toast.vue +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - {{title}} - - - {{ toast.state.message }} - - - - - - - - - - diff --git a/frontend/src/toast.js b/frontend/src/toast.js deleted file mode 100644 index 80b26860..00000000 --- a/frontend/src/toast.js +++ /dev/null @@ -1,54 +0,0 @@ -import {reactive} from 'vue'; - -const state = reactive({ - type: 'info', - active: false, - message: '', -}); - - -// ----------------------------------- -// Private Methods -// ----------------------------------- -let close; - -const dialogPromise = () => new Promise((resolve) => (close = resolve)); - -const open = (message) => { - state.message = message; - state.active = true; - return dialogPromise(); -}; - -const reset = () => { - state.active = false; - state.message = ''; - state.type = 'info'; -}; - -// ----------------------------------- -// Public interface -// ----------------------------------- - -export default { - get state() { - return state; - }, - success(message) { - state.type = 'success'; - return open(message); - }, - info(message) { - state.type = 'info'; - return open(message); - }, - error(message) { - state.type = 'error'; - return open(message); - }, - cancel() { - close(); - reset(); - }, -}; - diff --git a/frontend/src/views/AnalysisView.vue b/frontend/src/views/AnalysisView.vue index af850e1a..016152d0 100644 --- a/frontend/src/views/AnalysisView.vue +++ b/frontend/src/views/AnalysisView.vue @@ -1,4 +1,4 @@ - +54 - + diff --git a/frontend/test/components/Dialogs/Toast.spec.js b/frontend/test/components/Dialogs/RosalutionToast.spec.js similarity index 68% rename from frontend/test/components/Dialogs/Toast.spec.js rename to frontend/test/components/Dialogs/RosalutionToast.spec.js index c09334a0..ffe52d39 100644 --- a/frontend/test/components/Dialogs/Toast.spec.js +++ b/frontend/test/components/Dialogs/RosalutionToast.spec.js @@ -4,25 +4,29 @@ import sinon from 'sinon'; import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'; -import Toast from '@/components/Dialogs/Toast.vue'; -import toast from '@/toast.js'; +import RosalutionToast from '@/components/Dialogs/RosalutionToast.vue'; -describe('Dialog.vue', () => { +describe('Toast.vue', () => { let wrapper; let sandbox; + let toast; beforeAll(() => { sandbox = sinon.createSandbox(); }); beforeEach(() => { - wrapper = shallowMount(Toast, { + wrapper = shallowMount(RosalutionToast, { global: { components: { 'font-awesome-icon': FontAwesomeIcon, }, + stubs: { + transition: false, + }, }, }); + toast = wrapper.vm; }); afterEach(() => { @@ -63,13 +67,28 @@ describe('Dialog.vue', () => { it('should allow the user to close', async () => { toast.info('hello world'); await wrapper.vm.$nextTick(); + const toastContainer = wrapper.find('[data-test=toast-container]'); + expect(toastContainer.exists()).to.be.true; const closeIconElement = wrapper.get('[data-test=toast-close-button]'); - closeIconElement.trigger('click'); + await closeIconElement.trigger('click'); + + const closedContainer = wrapper.find('[data-test=toast-container]'); + expect(closedContainer.exists()).to.be.false; + }); + + it('displays different and multiple prompts to the toast', async () => { + toast.info('hello world first time'); await wrapper.vm.$nextTick(); - const toastContainer = wrapper.find('[data-test=toast-container]'); - expect(toastContainer.exists()).to.be.false; + expect(wrapper.html()).to.include('hello world first time'); + + toast.error('hello world error'); + await wrapper.vm.$nextTick(); + expect(wrapper.html()).to.include('hello world error'); + + toast.cancel(); + await wrapper.vm.$nextTick(); }); }); diff --git a/frontend/test/toast.spec.js b/frontend/test/toast.spec.js deleted file mode 100644 index d7d5ca26..00000000 --- a/frontend/test/toast.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -import {expect, describe, it} from 'vitest'; - -import toast from '@/toast.js'; - -describe('a reactive toast', () => { - describe('the that displays info', () => { - it('assigns message to the toast', () => { - toast.info('hello world info'); - expect(toast.state.message).to.equal('hello world info'); - }); - - it('can do multiple toasts one after another', () => { - toast.info('hello world first time'); - expect(toast.state.active).to.be.true; - expect(toast.state.message).to.equal('hello world first time'); - toast.cancel(); - - toast.info('hello world 2'); - expect(toast.state.active).to.be.true; - expect(toast.state.message).to.equal('hello world 2'); - toast.cancel(); - }); - }); - - describe('the that displays an error', () => { - it('assigns message to the toast', () => { - toast.error('hello world error'); - expect(toast.state.message).to.equal('hello world error'); - }); - }); - - describe('the that displays a success', () => { - it('assigns message to the toast', () => { - toast.error('hello world successs'); - expect(toast.state.message).to.equal('hello world successs'); - }); - }); - - describe('displays different multiple and different prompts', () => { - it('assigns message to the toast', () => { - toast.info('hello world first time'); - expect(toast.state.active).to.be.true; - expect(toast.state.message).to.equal('hello world first time'); - toast.cancel(); - - toast.error('hello world error'); - expect(toast.state.active).to.be.true; - expect(toast.state.message).to.equal('hello world error'); - toast.cancel(); - }); - }); - - it('makes it inactive when the toast is closed ', () => { - toast.info('hello world').then(async ()=>{ - expect(toast.state.active).to.be.false; - }); - expect(toast.state.active).to.be.true; - setTimeout(toast.cancel, 100); - }); - - it('resets on close', () => { - toast.info('Just letting you know this happened.').then(()=>{ - expect(toast.state.message).to.be.empty; - }); - }); -}); diff --git a/frontend/test/views/AnalysisView.spec.js b/frontend/test/views/AnalysisView.spec.js index 5a21397d..905306e2 100644 --- a/frontend/test/views/AnalysisView.spec.js +++ b/frontend/test/views/AnalysisView.spec.js @@ -9,12 +9,12 @@ import InputDialog from '@/components/Dialogs/InputDialog.vue'; import NotificationDialog from '@/components/Dialogs/NotificationDialog.vue'; import DiscussionSection from '@/components/AnalysisView/DiscussionSection.vue'; import SupplementalFormList from '@/components/AnalysisView/SupplementalFormList.vue'; +import RosalutionToast from '@/components/Dialogs/RosalutionToast.vue'; import SaveModal from '@/components/AnalysisView/SaveModal.vue'; import {authStore} from '@/stores/authStore.js'; import inputDialog from '@/inputDialog.js'; import notificationDialog from '@/notificationDialog.js'; -import toast from '@/toast.js'; import AnalysisView from '@/views/AnalysisView.vue'; @@ -46,6 +46,10 @@ function getMountedComponent(props) { components: { 'font-awesome-icon': FontAwesomeIcon, }, + stubs: { + transition: false, + RosalutionToast: false, + }, }, }); } @@ -170,14 +174,15 @@ describe('AnalysisView', () => { expect(mockVueRouterPush.called).to.be.true; }); - it('should have a copy button and show a toast with the copied content within it', () => { + it('should have a copy button and show a toast with the copied content within it', async () => { const geneBox = wrapper.getComponent(GeneBox); - geneBox.vm.$emit('clipboard-copy', 'NM_001017980.3:c.164G>T'); + await geneBox.vm.$emit('clipboard-copy', 'NM_001017980.3:c.164G>T'); + + const toastWrapper = wrapper.getComponent(RosalutionToast); - expect(toast.state.active).to.be.true; - expect(toast.state.type).to.equal('success'); - expect(toast.state.message).to.equal('Copied NM_001017980.3:c.164G>T to clipboard!'); + expect(toastWrapper.text()).to.contain('Success'); + expect(toastWrapper.text()).to.contain('Copied NM_001017980.3:c.164G>T to clipboard!'); }); }); @@ -193,6 +198,8 @@ describe('AnalysisView', () => { it('should mark an analysis as ready', async () => { wrapper = await updateAnalysisStoreLatestStatus(wrapper, 'Preparation'); + expect(mockAnalysisEventPush.called).to.be.false; + triggerAction(wrapper, 'Mark Ready'); expect(mockAnalysisEventPush.called).to.be.true; @@ -201,11 +208,11 @@ describe('AnalysisView', () => { it('should display success toast with correct message when marking analysis as ready', async () => { wrapper = await updateAnalysisStoreLatestStatus(wrapper, 'Preparation'); - triggerAction(wrapper, 'Mark Ready'); + await triggerAction(wrapper, 'Mark Ready'); + await wrapper.vm.$nextTick(); - expect(toast.state.active).to.be.true; - expect(toast.state.type).to.equal('success'); - expect(toast.state.message).to.equal('Analysis event \'ready\' successful.'); + const toastWrapper = wrapper.getComponent(RosalutionToast); + expect(toastWrapper.text()).to.contain('Analysis event \'ready\' successful.'); }); it('should display error toast with correct message when marking analysis as ready fails', async () => { @@ -218,9 +225,12 @@ describe('AnalysisView', () => { } catch (error) { console.error(error); } - expect(toast.state.active).to.be.true; - expect(toast.state.type).to.equal('error'); - expect(toast.state.message).to.equal('Error updating the event \'ready\'.'); + + await wrapper.vm.$nextTick(); + + const toastWrapper = wrapper.getComponent(RosalutionToast); + expect(toastWrapper.text()).to.contain('Error updating the event \'ready\'.'); + expect(toastWrapper.text()).to.contain('Error'); mockAnalysisEventPush.reset(); }); @@ -229,33 +239,35 @@ describe('AnalysisView', () => { wrapper = await updateAnalysisStoreLatestStatus(wrapper, 'Ready'); await triggerAction(wrapper, 'Mark Active'); + await wrapper.vm.$nextTick(); - expect(toast.state.active).to.be.true; - expect(toast.state.message).to.equal('Analysis event \'opened\' successful.'); - expect(toast.state.type).to.equal('success'); + const toastWrapper = wrapper.getComponent(RosalutionToast); + expect(toastWrapper.text()).to.contain('Success'); + expect(toastWrapper.text()).to.contain('Analysis event \'opened\' successful.'); }); - it('should display info toast with correct message when entering edit mode', () => { + it('should display info toast with correct message when entering edit mode', async () => { triggerAction(wrapper, 'Edit'); + await wrapper.vm.$nextTick(); - expect(toast.state.active).to.be.true; - expect(toast.state.type).to.equal('success'); - expect(toast.state.message).to.equal('Edit mode has been enabled.'); + const toastWrapper = wrapper.getComponent(RosalutionToast); + expect(toastWrapper.text()).to.contain('Edit mode has been enabled.'); + expect(toastWrapper.text()).to.contain('Success'); // This is done to reset the component to the non-editing state after testing. - triggerAction(wrapper, 'Edit'); + await triggerAction(wrapper, 'Edit'); }); - it('should display info toast with correct message when exiting edit mode', () => { + it('should display info toast with correct message when exiting edit mode', async () => { // Places the Initial wrapper into the 'Edit' mode - triggerAction(wrapper, 'Edit'); + await triggerAction(wrapper, 'Edit'); // Disabling the 'edit mode and notifying edits haven't been made - triggerAction(wrapper, 'Edit'); + await triggerAction(wrapper, 'Edit'); - expect(toast.state.active).to.be.true; - expect(toast.state.type).to.equal('info'); - expect(toast.state.message).to.equal('Edit mode has been disabled and changes have not been saved.'); + const toastWrapper = wrapper.getComponent(RosalutionToast); + expect(toastWrapper.text()).to.contain('Edit mode has been disabled and changes have not been saved.'); + expect(toastWrapper.text()).to.contain('Info'); }); }); @@ -548,23 +560,22 @@ describe('AnalysisView', () => { analysisStore.forceUpdate(analysisWithNewEvidence); }); - // INVESTIGATE ANGELINA - it.skip('updates section image content with input dialog', async () => { + it('updates section image content with input dialog', async () => { updateSectionImageMock.returns({ - section: 'Pedigree', + type: 'images-dataset', field: 'Pedigree', - image_id: 'different-image-635a89aea7b2f21802b74539', + value: [{file_id: 'different-image-635a89aea7b2f21802b74539'}], }); const pedigreeSection = wrapper.findComponent('[id=Pedigree]'); - pedigreeSection.vm.$emit('update-image', '635a89aea7b2f21802b74539', 'Pedigree', 'Pedigree'); + await pedigreeSection.vm.$emit('update-image', '635a89aea7b2f21802b74539', 'Pedigree', 'Pedigree'); const fakeImageForUpdate = {data: 'fakeImage.png'}; - inputDialog.confirmation(fakeImageForUpdate); + await inputDialog.confirmation(fakeImageForUpdate); - const reRenderedPedigreeSection = wrapper.findComponent('[id=Pedigree]'); + await pedigreeSection.vm.$nextTick(); expect(updateSectionImageMock.called).to.be.true; - expect(reRenderedPedigreeSection.props().content[0].value[0].file_id) + expect(pedigreeSection.props().content[0].value[0].file_id) .to.equal('different-image-635a89aea7b2f21802b74539'); }); @@ -720,16 +731,27 @@ describe('AnalysisView', () => { it('should display success toast when saving analysis changes', async () => { await triggerAction(wrapper, 'Edit'); + await wrapper.vm.$nextTick(); + + const toastWrapper = wrapper.getComponent(RosalutionToast); + expect(toastWrapper.text()).to.contain('Edit mode has been enabled.'); const saveModal = wrapper.findComponent(SaveModal); + await saveModal.vm.$emit('save'); - saveModal.vm.$emit('save'); - await wrapper.vm.$nextTick(); - await wrapper.vm.$nextTick(); + /** Ticks neccesarry for the events from Save to View be emitted and processed */ + await toastWrapper.vm.$nextTick(); + await toastWrapper.vm.$nextTick(); + + expect(toastWrapper.text()).to.contain('Analysis updated successfully.'); + + const closeIconElement = toastWrapper.get('[data-test=toast-close-button]'); + await closeIconElement.trigger('click'); - expect(toast.state.active).to.be.true; - expect(toast.state.type).to.equal('success'); - expect(toast.state.message).to.equal('Analysis updated successfully.'); + /** The Toast Hides itself, so while the component exists, its content is empty */ + const closedToast = toastWrapper.find('[data-test=toast]'); + expect(closedToast.exists()).to.be.false; + expect(toastWrapper.text()).to.contain(''); }); }); }); diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 327a14a5..d0a243c3 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -20,15 +20,27 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + "@babel/helper-validator-identifier@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== -"@babel/parser@^7.20.15", "@babel/parser@^7.21.3": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" - integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/parser@^7.25.3": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.2.tgz#fd7b6f487cfea09889557ef5d4eeb9ff9a5abd11" + integrity sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ== + dependencies: + "@babel/types" "^7.26.0" "@babel/parser@^7.25.4": version "7.25.6" @@ -46,6 +58,14 @@ "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" +"@babel/types@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.0.tgz#deabd08d6b753bc8e0f198f8709fb575e31774ff" + integrity sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -649,100 +669,90 @@ loupe "^3.1.1" tinyrainbow "^1.2.0" -"@vue/compiler-core@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.3.4.tgz#7fbf591c1c19e1acd28ffd284526e98b4f581128" - integrity sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g== +"@vue/compiler-core@3.5.12": + version "3.5.12" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.12.tgz#bd70b7dabd12b0b6f31bc53418ba3da77994c437" + integrity sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw== dependencies: - "@babel/parser" "^7.21.3" - "@vue/shared" "3.3.4" + "@babel/parser" "^7.25.3" + "@vue/shared" "3.5.12" + entities "^4.5.0" estree-walker "^2.0.2" - source-map-js "^1.0.2" - -"@vue/compiler-dom@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz#f56e09b5f4d7dc350f981784de9713d823341151" - integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w== - dependencies: - "@vue/compiler-core" "3.3.4" - "@vue/shared" "3.3.4" - -"@vue/compiler-sfc@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz#b19d942c71938893535b46226d602720593001df" - integrity sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ== - dependencies: - "@babel/parser" "^7.20.15" - "@vue/compiler-core" "3.3.4" - "@vue/compiler-dom" "3.3.4" - "@vue/compiler-ssr" "3.3.4" - "@vue/reactivity-transform" "3.3.4" - "@vue/shared" "3.3.4" + source-map-js "^1.2.0" + +"@vue/compiler-dom@3.5.12": + version "3.5.12" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz#456d631d11102535b7ee6fd954cf2c93158d0354" + integrity sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg== + dependencies: + "@vue/compiler-core" "3.5.12" + "@vue/shared" "3.5.12" + +"@vue/compiler-sfc@3.5.12": + version "3.5.12" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz#6688120d905fcf22f7e44d3cb90f8dabc4dd3cc8" + integrity sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw== + dependencies: + "@babel/parser" "^7.25.3" + "@vue/compiler-core" "3.5.12" + "@vue/compiler-dom" "3.5.12" + "@vue/compiler-ssr" "3.5.12" + "@vue/shared" "3.5.12" estree-walker "^2.0.2" - magic-string "^0.30.0" - postcss "^8.1.10" - source-map-js "^1.0.2" + magic-string "^0.30.11" + postcss "^8.4.47" + source-map-js "^1.2.0" -"@vue/compiler-ssr@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz#9d1379abffa4f2b0cd844174ceec4a9721138777" - integrity sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ== +"@vue/compiler-ssr@3.5.12": + version "3.5.12" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz#5f1a3fbd5c44b79a6dbe88729f7801d9c9218bde" + integrity sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA== dependencies: - "@vue/compiler-dom" "3.3.4" - "@vue/shared" "3.3.4" + "@vue/compiler-dom" "3.5.12" + "@vue/shared" "3.5.12" "@vue/devtools-api@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07" integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q== -"@vue/reactivity-transform@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz#52908476e34d6a65c6c21cd2722d41ed8ae51929" - integrity sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw== +"@vue/reactivity@3.5.12": + version "3.5.12" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.12.tgz#a2815d91842ed7b9e7e7936c851923caf6b6e603" + integrity sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg== dependencies: - "@babel/parser" "^7.20.15" - "@vue/compiler-core" "3.3.4" - "@vue/shared" "3.3.4" - estree-walker "^2.0.2" - magic-string "^0.30.0" + "@vue/shared" "3.5.12" -"@vue/reactivity@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.3.4.tgz#a27a29c6cd17faba5a0e99fbb86ee951653e2253" - integrity sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ== +"@vue/runtime-core@3.5.12": + version "3.5.12" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.12.tgz#849207f203d0fd82971f19574d30dbe7134c78c7" + integrity sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw== dependencies: - "@vue/shared" "3.3.4" + "@vue/reactivity" "3.5.12" + "@vue/shared" "3.5.12" -"@vue/runtime-core@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.3.4.tgz#4bb33872bbb583721b340f3088888394195967d1" - integrity sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA== +"@vue/runtime-dom@3.5.12": + version "3.5.12" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz#6d4de3df49a90a460b311b1100baa5e2d0d1c8c9" + integrity sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA== dependencies: - "@vue/reactivity" "3.3.4" - "@vue/shared" "3.3.4" + "@vue/reactivity" "3.5.12" + "@vue/runtime-core" "3.5.12" + "@vue/shared" "3.5.12" + csstype "^3.1.3" -"@vue/runtime-dom@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz#992f2579d0ed6ce961f47bbe9bfe4b6791251566" - integrity sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ== +"@vue/server-renderer@3.5.12": + version "3.5.12" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.12.tgz#79c6bc3860e4e4ef80d85653c5d03fd94b26574e" + integrity sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg== dependencies: - "@vue/runtime-core" "3.3.4" - "@vue/shared" "3.3.4" - csstype "^3.1.1" + "@vue/compiler-ssr" "3.5.12" + "@vue/shared" "3.5.12" -"@vue/server-renderer@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.3.4.tgz#ea46594b795d1536f29bc592dd0f6655f7ea4c4c" - integrity sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ== - dependencies: - "@vue/compiler-ssr" "3.3.4" - "@vue/shared" "3.3.4" - -"@vue/shared@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.3.4.tgz#06e83c5027f464eef861c329be81454bc8b70780" - integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ== +"@vue/shared@3.5.12": + version "3.5.12" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.12.tgz#f9e45b7f63f2c3f40d84237b1194b7f67de192e3" + integrity sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg== "@vue/test-utils@2.4.1": version "2.4.1" @@ -912,10 +922,10 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -csstype@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" - integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== +csstype@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" @@ -1499,13 +1509,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -magic-string@^0.30.0: - version "0.30.4" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.4.tgz#c2c683265fc18dda49b56fc7318d33ca0332c98c" - integrity sha512-Q/TKtsC5BPm0kGqgBIF9oXAs/xEf2vRKiIB4wCRQTJOQIByZ1d+NnUOotvJOvNpi5RNIgVOMC3pOuaP1ZTDlVg== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - magic-string@^0.30.11: version "0.30.11" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.11.tgz#301a6f93b3e8c2cb13ac1a7a673492c0dfd12954" @@ -1584,11 +1587,6 @@ ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@^3.3.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" - integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== - nanoid@^3.3.7: version "3.3.7" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" @@ -1735,15 +1733,6 @@ postcss-selector-parser@^6.0.13: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss@^8.1.10: - version "8.4.31" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" - integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== - dependencies: - nanoid "^3.3.6" - picocolors "^1.0.0" - source-map-js "^1.0.2" - postcss@^8.4.38: version "8.4.38" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" @@ -1753,7 +1742,7 @@ postcss@^8.4.38: picocolors "^1.0.0" source-map-js "^1.2.0" -postcss@^8.4.43: +postcss@^8.4.43, postcss@^8.4.47: version "8.4.47" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== @@ -1905,11 +1894,6 @@ sirv@^2.0.4: mrmime "^2.0.0" totalist "^3.0.0" -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - source-map-js@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" @@ -2163,16 +2147,16 @@ vue-router@4.2.5: dependencies: "@vue/devtools-api" "^6.5.0" -vue@3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/vue/-/vue-3.3.4.tgz#8ed945d3873667df1d0fcf3b2463ada028f88bd6" - integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw== +vue@3.5.12: + version "3.5.12" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.12.tgz#e08421c601b3617ea2c9ef0413afcc747130b36c" + integrity sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg== dependencies: - "@vue/compiler-dom" "3.3.4" - "@vue/compiler-sfc" "3.3.4" - "@vue/runtime-dom" "3.3.4" - "@vue/server-renderer" "3.3.4" - "@vue/shared" "3.3.4" + "@vue/compiler-dom" "3.5.12" + "@vue/compiler-sfc" "3.5.12" + "@vue/runtime-dom" "3.5.12" + "@vue/server-renderer" "3.5.12" + "@vue/shared" "3.5.12" webidl-conversions@^7.0.0: version "7.0.0"