diff --git a/client/.postcssrc.js b/client/.postcssrc.js deleted file mode 100644 index 39ebf318..00000000 --- a/client/.postcssrc.js +++ /dev/null @@ -1,10 +0,0 @@ -// https://github.com/michael-ciniawsky/postcss-load-config - -module.exports = { - plugins: { - 'postcss-import': {}, - 'postcss-url': {}, - // to edit target browsers: use "browserslist" field in package.json - autoprefixer: {}, - }, -}; diff --git a/client/.postcssrc.json b/client/.postcssrc.json new file mode 100644 index 00000000..8752e22e --- /dev/null +++ b/client/.postcssrc.json @@ -0,0 +1,7 @@ +{ + "plugins": { + "postcss-import": {}, + "postcss-url": {}, + "autoprefixer": {} + } +} diff --git a/client/build/build.js b/client/build/build.js deleted file mode 100644 index 78ba7f23..00000000 --- a/client/build/build.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; -require('./check-versions')(); - -process.env.NODE_ENV = 'production'; - -const ora = require('ora'); -const rm = require('rimraf'); -const path = require('path'); -const chalk = require('chalk'); -const webpack = require('webpack'); -const config = require('../config'); -const webpackConfig = require('./webpack.prod.conf'); - -const spinner = ora('building for production...'); -spinner.start(); - -rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), (err) => { - if (err) throw err; - webpack(webpackConfig, (err, stats) => { - spinner.succeed(); - if (err) throw err; - process.stdout.write( - stats.toString({ - colors: true, - modules: false, - children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. - chunks: false, - chunkModules: false, - }) + '\n\n' - ); - - if (stats.hasErrors()) { - console.log(chalk.red(' Build failed with errors.\n')); - process.exit(1); - } - - console.log(chalk.cyan(' Build complete.\n')); - console.log( - chalk.yellow( - ' Tip: built files are meant to be served over an HTTP server.\n' + - " Opening index.html over file:// won't work.\n" - ) - ); - }); -}); diff --git a/client/build/check-versions.js b/client/build/check-versions.js deleted file mode 100644 index 3999006d..00000000 --- a/client/build/check-versions.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict'; -const chalk = require('chalk'); -const semver = require('semver'); -const packageConfig = require('../package.json'); -const shell = require('shelljs'); - -function exec(cmd) { - return require('child_process').execSync(cmd).toString().trim(); -} - -const versionRequirements = [ - { - name: 'node', - currentVersion: semver.clean(process.version), - versionRequirement: packageConfig.engines.node, - }, -]; - -if (shell.which('npm')) { - versionRequirements.push({ - name: 'npm', - currentVersion: exec('npm --version'), - versionRequirement: packageConfig.engines.npm, - }); -} - -module.exports = function () { - const warnings = []; - - for (let i = 0; i < versionRequirements.length; i++) { - const mod = versionRequirements[i]; - - if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { - warnings.push( - mod.name + ': ' + chalk.red(mod.currentVersion) + ' should be ' + chalk.green(mod.versionRequirement) - ); - } - } - - if (warnings.length) { - console.log(''); - console.log(chalk.yellow('To use this template, you must update following to modules:')); - console.log(); - - for (let i = 0; i < warnings.length; i++) { - const warning = warnings[i]; - console.log(' ' + warning); - } - - console.log(); - process.exit(1); - } -}; diff --git a/client/build/utils.js b/client/build/utils.js index 80059123..d193d38b 100644 --- a/client/build/utils.js +++ b/client/build/utils.js @@ -3,7 +3,7 @@ const path = require('path'); const config = require('../config'); const packageConfig = require('../package.json'); -const isDev = process.env.NODE_ENV !== 'production'; +const isDev = import.meta.env.MODE !== 'production'; const assetsPath = (_path) => { const assetsSubDirectory = isDev ? config.dev.assetsSubDirectory : config.build.assetsSubDirectory; diff --git a/client/config/prod-dha.env.js b/client/config/prod-dha.env.js index 5efa78c3..24689baf 100644 --- a/client/config/prod-dha.env.js +++ b/client/config/prod-dha.env.js @@ -1,17 +1,7 @@ -'use strict'; -module.exports = { - /* - * ENV variables used in JS code need to be stringyfied, as they will be replaced in the code, and JS needs quotes - * around strings - */ - VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL, - - /* - * Vars used in HTML templates don't need to be stringyfied, as HTML does not need them to have quotes - */ - // vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv +const config = { VUE_APP_FAVICON_32: 'https://skillbox-my-detailhandel-dha-prod.s3.eu-central-1.amazonaws.com/myDHA-favicon.png', VUE_APP_FAVICON_16: 'https://skillbox-my-detailhandel-dha-prod.s3.eu-central-1.amazonaws.com/myDHA-favicon.png', VUE_APP_TITLE: 'myDHA', - // ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^ }; + +export default config; diff --git a/client/config/prod-dhf.env.js b/client/config/prod-dhf.env.js index fa5b1fca..4db3abc8 100644 --- a/client/config/prod-dhf.env.js +++ b/client/config/prod-dhf.env.js @@ -1,17 +1,7 @@ -'use strict'; -module.exports = { - /* - * ENV variables used in JS code need to be stringyfied, as they will be replaced in the code, and JS needs quotes - * around strings - */ - VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL, - - /* - * Vars used in HTML templates don't need to be stringyfied, as HTML does not need them to have quotes - */ - // vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv +const config = { VUE_APP_FAVICON_32: 'https://skillbox-my-detailhandel-dhf-prod.s3.eu-central-1.amazonaws.com/myDHF-favicon.png', VUE_APP_FAVICON_16: 'https://skillbox-my-detailhandel-dhf-prod.s3.eu-central-1.amazonaws.com/myDHF-favicon.png', VUE_APP_TITLE: 'myDHF', - // ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^ }; + +export default config; diff --git a/client/config/prod-my-kv.env.js b/client/config/prod-my-kv.env.js index 797a8bca..26cf4771 100644 --- a/client/config/prod-my-kv.env.js +++ b/client/config/prod-my-kv.env.js @@ -1,17 +1,7 @@ -'use strict'; -module.exports = { - /* - * ENV variables used in JS code need to be stringyfied, as they will be replaced in the code, and JS needs quotes - * around strings - */ - VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL, - - /* - * Vars used in HTML templates don't need to be stringyfied, as HTML does not need them to have quotes - */ - // vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv +const config = { VUE_APP_FAVICON_32: 'https://skillbox-my-kv-prod.s3-eu-west-1.amazonaws.com/mykv-favicon.png', VUE_APP_FAVICON_16: 'https://skillbox-my-kv-prod.s3-eu-west-1.amazonaws.com/mykv-favicon.png', VUE_APP_TITLE: 'myKV', - // ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^ }; + +export default config; diff --git a/client/config/prod.env.js b/client/config/prod.env.js deleted file mode 100644 index b85354b5..00000000 --- a/client/config/prod.env.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; -const { merge } = require('webpack-merge'); - -const values = { - NODE_ENV: '"production"', - HEP_URL: JSON.stringify(process.env.HEP_URL), - MATOMO_HOST: JSON.stringify(process.env.MATOMO_HOST), - MATOMO_SITE_ID: JSON.stringify(process.env.MATOMO_SITE_ID), - LOGOUT_REDIRECT_URL: JSON.stringify(process.env.LOGOUT_REDIRECT_URL), - VUE_APP_FLAVOR: JSON.stringify(process.env.APP_FLAVOR), - SENTRY_DSN: JSON.stringify(process.env.SENTRY_JAVASCRIPT_DSN), - SENTRY_ENVIRONMENT: JSON.stringify(process.env.SENTRY_ENV), - /* - * ENV variables used in JS code need to be stringyfied, as they will be replaced (in place) in the code, - * and JS needs quotes around strings - * see https://cli.vuejs.org/guide/mode-and-env.html#using-env-variables-in-client-side-code - */ - VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL, - - /* - * Vars used in HTML templates don't need to be stringyfied, as HTML does not need them to have quotes - */ - // vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv - VUE_APP_FAVICON_32: '/static/favicon-32x32.png', - VUE_APP_FAVICON_16: '/static/favicon-16x16.png', - VUE_APP_TITLE: 'mySkillbox', - // ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^ -}; - -switch (process.env.APP_FLAVOR) { - case 'my-kv': - module.exports = merge(values, require('./prod-my-kv.env.js')); - break; - case 'my-dhf': - module.exports = merge(values, require('./prod-dhf.env.js')); - break; - case 'my-dha': - module.exports = merge(values, require('./prod-dha.env.js')); - break; - default: - // we are on the skillbox APP_FLAVOR - module.exports = values; -} diff --git a/client/cypress.frontend.ts b/client/cypress.frontend.ts index e79eef78..94633644 100644 --- a/client/cypress.frontend.ts +++ b/client/cypress.frontend.ts @@ -37,11 +37,7 @@ export default defineConfig({ component: { devServer: { framework: 'vue', - bundler: 'webpack', - webpackConfig: async () => { - const webpackConfig = await require('./build/webpack.dev.conf'); - return webpackConfig; - }, + bundler: 'vite', }, }, }); diff --git a/client/cypress/e2e/frontend/modules/snapshots.spec.js b/client/cypress/e2e/frontend/modules/snapshots.spec.js index feb5e6d8..becc562b 100644 --- a/client/cypress/e2e/frontend/modules/snapshots.spec.js +++ b/client/cypress/e2e/frontend/modules/snapshots.spec.js @@ -245,7 +245,8 @@ describe('Snapshot', () => { cy.visit('module/miteinander-reden/snapshots'); cy.getByDataCy('snapshot-link').should('have.text', 'Old Title'); cy.getByDataCy('rename-snapshot-button').click(); - cy.getByDataCy('edit-name-input').clear().type(newTitle); + cy.getByDataCy('edit-name-input').clear(); + cy.getByDataCy('edit-name-input').type(newTitle); cy.getByDataCy('modal-save-button').click(); cy.getByDataCy('snapshot-link').should('have.text', 'New Title'); waitNTimes(5); diff --git a/client/cypress/e2e/frontend/rooms/room-page.spec.js b/client/cypress/e2e/frontend/rooms/room-page.spec.js index 7f422769..44ab8557 100644 --- a/client/cypress/e2e/frontend/rooms/room-page.spec.js +++ b/client/cypress/e2e/frontend/rooms/room-page.spec.js @@ -1,12 +1,12 @@ -import { getMinimalMe } from '../../../support/helpers'; +import { getMinimalMe } from '../../../support/helpers' describe('The Room Page (Teacher)', () => { - const MeQuery = getMinimalMe(); - const selectedClass = MeQuery.me.selectedClass; - const entryText = 'something should be here'; - const entryTitle = 'some title'; - const slug = 'ein-historisches-festival'; - const id = btoa('RoomNode:1'); + const MeQuery = getMinimalMe() + const selectedClass = MeQuery.me.selectedClass + const entryText = 'something should be here' + const entryTitle = 'some title' + const slug = 'ein-historisches-festival' + const id = btoa('RoomNode:1') const room = { id, slug, @@ -15,11 +15,11 @@ describe('The Room Page (Teacher)', () => { roomEntries: { edges: [], }, - }; + } const RoomEntriesQuery = { room, - }; + } const operations = { MeQuery, @@ -46,38 +46,42 @@ describe('The Room Page (Teacher)', () => { errors: [], }, }, - }; + } const checkRadioButton = () => { - cy.get('.base-input-container__input:checked + .base-input-container__radiobutton svg').should('have.length', 1); - }; + cy.get( + '.base-input-container__input:checked + .base-input-container__radiobutton svg' + ).should('have.length', 1) + } beforeEach(() => { - cy.setup(); - }); + cy.setup() + }) it('displays new room entry with author name', () => { cy.mockGraphqlOps({ operations, - }); - cy.visit(`/room/${slug}`); + }) + cy.visit(`/room/${slug}`) - cy.getByDataCy('add-room-entry-button').click(); - cy.getByDataCy('add-content-link').first().click(); - cy.getByDataCy('choose-text-widget').click(); - cy.getByDataCy('input-with-label-input').type(entryTitle); + cy.getByDataCy('add-room-entry-button').click() + cy.getByDataCy('add-content-link').first().click() + cy.getByDataCy('choose-text-widget').click() + cy.getByDataCy('input-with-label-input').type(entryTitle) - cy.get('.tip-tap__editor').type(entryText); - cy.getByDataCy('save-button').click(); + cy.get('.tip-tap__editor').type(entryText) + cy.getByDataCy('save-button').click() - cy.get('.room-entry__content:first').should('contain', entryText).should('contain', 'Rachel Green'); - }); + cy.get('.room-entry__content:first') + .should('contain', entryText) + .should('contain', 'Rachel Green') + }) // todo: re-enable once cypress can do it correctly it.skip('changes visibility of a room', () => { const MeQuery = getMinimalMe({ isTeacher: true, - }); + }) const operations = { MeQuery, RoomEntriesQuery, @@ -90,61 +94,72 @@ describe('The Room Page (Teacher)', () => { }, }, }, - }; + } cy.mockGraphqlOps({ operations, - }); + }) - cy.visit(`/room/${slug}`); - cy.getByDataCy('room-visibility-status').should('contain', 'alle Lernenden'); - cy.getByDataCy('toggle-more-actions-menu').click(); - cy.getByDataCy('change-visibility').click(); - cy.getByDataCy('modal-title').should('contain', 'Sichtbarkeit anpassen'); - cy.get('.change-visibility__radio').should('have.length', 2); - cy.get('.change-visibility__radio--selected').should('have.length', 1); - checkRadioButton(); - cy.get('.change-visibility__radio--selected').should('have.length', 1).should('contain', 'alle Lernenden'); - checkRadioButton(); - cy.getByDataCy('select-option').eq(0).click(); - cy.get('.change-visibility__radio--selected').should('have.length', 1); - checkRadioButton(); - cy.getByDataCy('select-option').eq(1).click(); - cy.getByDataCy('select-option').eq(1).click(); - cy.get('.change-visibility__radio--selected').should('have.length', 1).should('contain', 'eigenen Beiträge'); - checkRadioButton(); - cy.getByDataCy('modal-save-button').click(); - cy.getByDataCy('room-visibility-status').should('contain', 'eigenen Beiträge'); - cy.getByDataCy('toggle-more-actions-menu').click(); - cy.getByDataCy('change-visibility').click(); - cy.getByDataCy('modal-title').should('contain', 'Sichtbarkeit anpassen'); - cy.get('.change-visibility__radio--selected').should('have.length', 1).should('contain', 'eigenen Beiträge'); - checkRadioButton(); - }); + cy.visit(`/room/${slug}`) + cy.getByDataCy('room-visibility-status').should('contain', 'alle Lernenden') + cy.getByDataCy('toggle-more-actions-menu').click() + cy.getByDataCy('change-visibility').click() + cy.getByDataCy('modal-title').should('contain', 'Sichtbarkeit anpassen') + cy.get('.change-visibility__radio').should('have.length', 2) + cy.get('.change-visibility__radio--selected').should('have.length', 1) + checkRadioButton() + cy.get('.change-visibility__radio--selected') + .should('have.length', 1) + .should('contain', 'alle Lernenden') + checkRadioButton() + cy.getByDataCy('select-option').eq(0).click() + cy.get('.change-visibility__radio--selected').should('have.length', 1) + checkRadioButton() + cy.getByDataCy('select-option').eq(1).click() + cy.getByDataCy('select-option').eq(1).click() + cy.get('.change-visibility__radio--selected') + .should('have.length', 1) + .should('contain', 'eigenen Beiträge') + checkRadioButton() + cy.getByDataCy('modal-save-button').click() + cy.getByDataCy('room-visibility-status').should( + 'contain', + 'eigenen Beiträge' + ) + cy.getByDataCy('toggle-more-actions-menu').click() + cy.getByDataCy('change-visibility').click() + cy.getByDataCy('modal-title').should('contain', 'Sichtbarkeit anpassen') + cy.get('.change-visibility__radio--selected') + .should('have.length', 1) + .should('contain', 'eigenen Beiträge') + checkRadioButton() + }) it('deletes the room and goes back to the overview', () => { - const MeQuery = getMinimalMe(); - const schoolClass = MeQuery.me.selectedClass; + const MeQuery = getMinimalMe() + const schoolClass = MeQuery.me.selectedClass const roomToDelete = { - id: btoa('RoomNode:room-to-delete'), + id: window.btoa('RoomNode:room-to-delete'), + title: 'Delete Me', schoolClass, slug: 'delete-me', roomEntries: { edges: [], }, - }; + } const otherRoom = { - id: btoa('RoomNode:otherRoom'), + id: window.btoa('RoomNode:otherRoom'), slug: 'other-slug', + title: 'Other Room', schoolClass, - }; - let rooms = [roomToDelete, otherRoom]; + } + let rooms = [roomToDelete, otherRoom] const operations = { MeQuery, RoomsQuery() { return { rooms, - }; + } }, RoomEntriesQuery: { room: roomToDelete, @@ -154,31 +169,32 @@ describe('The Room Page (Teacher)', () => { success: true, }, }, - }; + } cy.mockGraphqlOps({ operations, - }); + }) - cy.visit(`/rooms`); - cy.getByDataCy('room-widget').should('have.length', 2); - cy.getByDataCy('room-widget').first().click(); - cy.getByDataCy('toggle-more-actions-menu').click(); + cy.visit(`/rooms`) + cy.getByDataCy('room-widget').should('have.length', 2) + cy.getByDataCy('room-widget').first().click() + cy.getByDataCy('room-title').should('contain', 'Delete Me') + cy.getByDataCy('toggle-more-actions-menu').click() cy.getByDataCy('delete-room').within(() => { - cy.get('a').click(); - }); - cy.getByDataCy('modal-save-button').click(); - cy.url().should('include', 'rooms'); - cy.getByDataCy('room-widget').should('have.length', 1); - }); + cy.get('a').click() + }) + cy.getByDataCy('modal-save-button').click() + cy.url().should('include', 'rooms') + cy.getByDataCy('room-widget').should('have.length', 1) + }) it('changes class while on room page', () => { - const { me } = MeQuery; + const { me } = MeQuery const otherClass = { - id: btoa('SchoolClassNode:34'), + id: window.btoa('SchoolClassNode:34'), name: 'Other Class', readOnly: false, - }; - let selectedClass = me.selectedClass; + } + let selectedClass = me.selectedClass const operations = { MeQuery: () => { return { @@ -187,16 +203,16 @@ describe('The Room Page (Teacher)', () => { schoolClasses: [...me.schoolClasses, otherClass], selectedClass, }, - }; + } }, RoomEntriesQuery, UpdateSettings() { - selectedClass = otherClass; + selectedClass = otherClass return { updateSettings: { success: true, }, - }; + } }, ModuleDetailsQuery: {}, MySchoolClassQuery: () => { @@ -204,32 +220,32 @@ describe('The Room Page (Teacher)', () => { me: { selectedClass, }, - }; + } }, RoomsQuery: { rooms: [], }, - }; + } cy.mockGraphqlOps({ operations, - }); - cy.visit(`/room/${slug}`); - cy.getByDataCy('room-title').should('contain', 'A Room'); - cy.selectClass('Other Class'); - cy.url().should('include', 'rooms'); - cy.getByDataCy('current-class-name').should('contain', 'Other Class'); - }); -}); + }) + cy.visit(`/room/${slug}`) + cy.getByDataCy('room-title').should('contain', 'A Room') + cy.selectClass('Other Class') + cy.url().should('include', 'rooms') + cy.getByDataCy('current-class-name').should('contain', 'Other Class') + }) +}) describe('The Room Page (student)', () => { - const slug = 'ein-historisches-festival'; - const MeQuery = getMinimalMe({ isTeacher: false }); - const { me } = MeQuery; - const id = atob(me.id).split(':')[1]; - const authorId = btoa(`PublicUserNode:${id}`); - const entrySlug = 'entry-slug'; - const { selectedClass } = me; + const slug = 'ein-historisches-festival' + const MeQuery = getMinimalMe({ isTeacher: false }) + const { me } = MeQuery + const id = atob(me.id).split(':')[1] + const authorId = btoa(`PublicUserNode:${id}`) + const entrySlug = 'entry-slug' + const { selectedClass } = me const roomEntry = { id: 'entry-id', slug: entrySlug, @@ -250,7 +266,7 @@ describe('The Room Page (student)', () => { lastName: 'Was Heiri', avatarUrl: '', }, - }; + } const room = { id, slug, @@ -263,55 +279,58 @@ describe('The Room Page (student)', () => { }, ], }, - }; + } const RoomEntriesQuery = { room, - }; + } beforeEach(() => { - cy.setup(); - }); + cy.setup() + }) it('room actions should not exist for student', () => { const operations = { MeQuery: getMinimalMe({ isTeacher: false }), RoomEntriesQuery, - }; + } cy.mockGraphqlOps({ operations, - }); - cy.visit(`/room/${slug}`); + }) + cy.visit(`/room/${slug}`) - cy.getByDataCy('room-title').should('exist'); - cy.getByDataCy('room-actions').should('not.exist'); - }); + cy.getByDataCy('room-title').should('exist') + cy.getByDataCy('room-actions').should('not.exist') + }) it('creates a room entry', () => { - const MeQuery = getMinimalMe({ isTeacher: false }); + const MeQuery = getMinimalMe({ isTeacher: false }) const room = { id: 'some-room', roomEntries: { edges: [], }, - }; + } const operations = { MeQuery, RoomEntriesQuery: { room, }, - }; + } cy.mockGraphqlOps({ operations, - }); + }) - cy.visit(`/room/${slug}`); - cy.getByDataCy('add-room-entry-button').click(); + cy.visit(`/room/${slug}`) + cy.getByDataCy('add-room-entry-button').click() - cy.getByDataCy('content-form-section-title').should('have.text', 'Titel (Pflichtfeld)'); - }); + cy.getByDataCy('content-form-section-title').should( + 'have.text', + 'Titel (Pflichtfeld)' + ) + }) it('edits own room entry', () => { const room = { @@ -325,7 +344,7 @@ describe('The Room Page (student)', () => { }, ], }, - }; + } const operations = { MeQuery: MeQuery, RoomEntriesQuery: { @@ -334,15 +353,15 @@ describe('The Room Page (student)', () => { RoomEntryQuery: { roomEntry, }, - }; + } cy.mockGraphqlOps({ operations, - }); - cy.visit(`/room/${slug}`); - cy.getByDataCy('room-entry-actions').click(); - cy.getByDataCy('edit-room-entry').click(); - cy.location('pathname').should('include', entrySlug); - }); + }) + cy.visit(`/room/${slug}`) + cy.getByDataCy('room-entry-actions').click() + cy.getByDataCy('edit-room-entry').click() + cy.location('pathname').should('include', entrySlug) + }) it('deletes room entry', () => { const DeleteRoomEntry = { @@ -351,57 +370,57 @@ describe('The Room Page (student)', () => { errors: null, roomSlug: slug, }, - }; + } const operations = { MeQuery, RoomEntriesQuery, DeleteRoomEntry, - }; + } cy.mockGraphqlOps({ operations, - }); + }) - cy.visit(`/room/${slug}`); - cy.getByDataCy('room-entry').should('have.length', 1); - cy.getByDataCy('room-entry-actions').click(); - cy.getByDataCy('delete-room-entry').click(); - cy.getByDataCy('delete-room-entry').should('not.exist'); - cy.getByDataCy('modal-save-button').click(); - cy.getByDataCy('room-entry').should('have.length', 0); - }); + cy.visit(`/room/${slug}`) + cy.getByDataCy('room-entry').should('have.length', 1) + cy.getByDataCy('room-entry-actions').click() + cy.getByDataCy('delete-room-entry').click() + cy.getByDataCy('delete-room-entry').should('not.exist') + cy.getByDataCy('modal-save-button').click() + cy.getByDataCy('room-entry').should('have.length', 0) + }) it('shows room entries with comment count', () => { const operations = { MeQuery, RoomEntriesQuery, - }; + } cy.mockGraphqlOps({ operations, - }); + }) - cy.visit(`/room/${slug}`); + cy.visit(`/room/${slug}`) cy.getByDataCy('room-entry') .should('have.length', 1) .within(() => { - cy.getByDataCy('entry-count').should('contain.text', '2'); - }); - }); + cy.getByDataCy('entry-count').should('contain.text', '2') + }) + }) it('does not show actions on mobile', () => { const operations = { MeQuery, RoomEntriesQuery, - }; + } cy.mockGraphqlOps({ operations, - }); - cy.viewport('iphone-8'); + }) + cy.viewport('iphone-8') - cy.visit(`/room/${slug}`); - cy.getByDataCy('room-actions').should('not.exist'); - cy.getByDataCy('room-entry').should('have.length', 1); - cy.getByDataCy('room-entry-actions').should('not.be.visible'); - }); -}); + cy.visit(`/room/${slug}`) + cy.getByDataCy('room-actions').should('not.exist') + cy.getByDataCy('room-entry').should('have.length', 1) + cy.getByDataCy('room-entry-actions').should('not.be.visible') + }) +}) diff --git a/client/index.html b/client/index.html index a2f288ef..3d8524db 100644 --- a/client/index.html +++ b/client/index.html @@ -4,17 +4,15 @@ - - <%= htmlWebpackPlugin.options.VUE_APP_TITLE %> - + _APP_TITLE_ - - + + @@ -37,10 +35,8 @@ -
-
-
- +
+ diff --git a/client/package-lock.json b/client/package-lock.json index a5b47ecb..1ebaa7ea 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -19,6 +19,7 @@ "@graphql-tools/jest-transform": "^1.2.2", "@graphql-tools/mock": "^8.6.5", "@graphql-tools/schema": "^8.3.7", + "@rollup/plugin-graphql": "^1.1.0", "@sentry/vue": "^7.45.0", "@sentry/webpack-plugin": "^1.20.0", "@tiptap/core": "^2.0.0-beta.174", @@ -30,6 +31,7 @@ "@tiptap/vue-3": "^2.0.0-beta.90", "@typescript-eslint/eslint-plugin": "^5.10.0", "@typescript-eslint/parser": "^5.10.0", + "@vitejs/plugin-vue": "^3.0.3", "@vue/apollo-composable": "^4.0.0-beta.1", "@vue/apollo-option": "^4.0.0-alpha.16", "@vue/compat": "3.2.30", @@ -84,16 +86,18 @@ "shelljs": "^0.8.5", "survey-knockout": "^1.9.41", "ts-loader": "^8.3.0", - "typescript": "^4.5.4", + "typescript": "^4.6.4", "uploadcare-widget": "^3.6.0", "url-loader": "^4.1.1", "vee-validate": "^4.5.10", + "vite": "^3.1.0", "vue": "3.2.30", "vue-loader": "^16.8.3", "vue-matomo": "^4.2.0", "vue-router": "^4.0.14", "vue-scrollto": "^2.20.0", "vue-style-loader": "^3.0.1", + "vue-tsc": "^0.40.4", "vue-vimeo-player": "^1.1.2", "vuex": "4.0.1", "webpack": "^5.67.0", @@ -2057,6 +2061,36 @@ "node": ">=10.0.0" } }, + "node_modules/@esbuild/android-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -3347,6 +3381,31 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@rollup/plugin-graphql": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-graphql/-/plugin-graphql-1.1.0.tgz", + "integrity": "sha512-X+H6oFlprDlnO3D0UiEytdW97AMphPXO0C7KunS7i/rBXIGQRQVDU5WKTXnBu2tfyYbjCTtfhXMSGI0i885PNg==", + "dependencies": { + "@rollup/pluginutils": "^4.0.0", + "graphql-tag": "^2.2.2" + }, + "peerDependencies": { + "graphql": ">=0.9.0", + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/@sentry-internal/tracing": { "version": "7.45.0", "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.45.0.tgz", @@ -4252,6 +4311,164 @@ "weakmap-polyfill": "2.0.4" } }, + "node_modules/@vitejs/plugin-vue": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz", + "integrity": "sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==", + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^3.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/code-gen": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/@volar/code-gen/-/code-gen-0.40.13.tgz", + "integrity": "sha512-4gShBWuMce868OVvgyA1cU5WxHbjfEme18Tw6uVMfweZCF5fB2KECG0iPrA9D54vHk3FeHarODNwgIaaFfUBlA==", + "dependencies": { + "@volar/source-map": "0.40.13" + } + }, + "node_modules/@volar/source-map": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-0.40.13.tgz", + "integrity": "sha512-dbdkAB2Nxb0wLjAY5O64o3ywVWlAGONnBIoKAkXSf6qkGZM+nJxcizsoiI66K+RHQG0XqlyvjDizfnTxr+6PWg==", + "dependencies": { + "@vue/reactivity": "3.2.38" + } + }, + "node_modules/@volar/source-map/node_modules/@vue/reactivity": { + "version": "3.2.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.38.tgz", + "integrity": "sha512-6L4myYcH9HG2M25co7/BSo0skKFHpAN8PhkNPM4xRVkyGl1K5M3Jx4rp5bsYhvYze2K4+l+pioN4e6ZwFLUVtw==", + "dependencies": { + "@vue/shared": "3.2.38" + } + }, + "node_modules/@volar/source-map/node_modules/@vue/shared": { + "version": "3.2.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.38.tgz", + "integrity": "sha512-dTyhTIRmGXBjxJE+skC8tTWCGLCVc4wQgRRLt8+O9p5ewBAjoBwtCAkLPrtToSr1xltoe3st21Pv953aOZ7alg==" + }, + "node_modules/@volar/typescript-faster": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/@volar/typescript-faster/-/typescript-faster-0.40.13.tgz", + "integrity": "sha512-uy+TlcFkKoNlKEnxA4x5acxdxLyVDIXGSc8cYDNXpPKjBKXrQaetzCzlO3kVBqu1VLMxKNGJMTKn35mo+ILQmw==", + "dependencies": { + "semver": "^7.3.7" + } + }, + "node_modules/@volar/typescript-faster/node_modules/semver": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", + "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@volar/vue-language-core": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/@volar/vue-language-core/-/vue-language-core-0.40.13.tgz", + "integrity": "sha512-QkCb8msi2KUitTdM6Y4kAb7/ZlEvuLcbBFOC2PLBlFuoZwyxvSP7c/dBGmKGtJlEvMX0LdCyrg5V2aBYxD38/Q==", + "dependencies": { + "@volar/code-gen": "0.40.13", + "@volar/source-map": "0.40.13", + "@vue/compiler-core": "^3.2.38", + "@vue/compiler-dom": "^3.2.38", + "@vue/compiler-sfc": "^3.2.38", + "@vue/reactivity": "^3.2.38", + "@vue/shared": "^3.2.38" + } + }, + "node_modules/@volar/vue-language-core/node_modules/@vue/compiler-core": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", + "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "source-map": "^0.6.1" + } + }, + "node_modules/@volar/vue-language-core/node_modules/@vue/compiler-dom": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz", + "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==", + "dependencies": { + "@vue/compiler-core": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "node_modules/@volar/vue-language-core/node_modules/@vue/compiler-sfc": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz", + "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.47", + "@vue/compiler-dom": "3.2.47", + "@vue/compiler-ssr": "3.2.47", + "@vue/reactivity-transform": "3.2.47", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7", + "postcss": "^8.1.10", + "source-map": "^0.6.1" + } + }, + "node_modules/@volar/vue-language-core/node_modules/@vue/compiler-ssr": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz", + "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==", + "dependencies": { + "@vue/compiler-dom": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "node_modules/@volar/vue-language-core/node_modules/@vue/reactivity": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.47.tgz", + "integrity": "sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==", + "dependencies": { + "@vue/shared": "3.2.47" + } + }, + "node_modules/@volar/vue-language-core/node_modules/@vue/reactivity-transform": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz", + "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.47", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7" + } + }, + "node_modules/@volar/vue-language-core/node_modules/@vue/shared": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz", + "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==" + }, + "node_modules/@volar/vue-typescript": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/@volar/vue-typescript/-/vue-typescript-0.40.13.tgz", + "integrity": "sha512-o7bNztwjs8JmbQjVkrnbZUOfm7q4B8ZYssETISN1tRaBdun6cfNqgpkvDYd+VUBh1O4CdksvN+5BUNnwAz4oCQ==", + "dependencies": { + "@volar/code-gen": "0.40.13", + "@volar/typescript-faster": "0.40.13", + "@volar/vue-language-core": "0.40.13" + } + }, "node_modules/@vue/apollo-composable": { "version": "4.0.0-beta.1", "resolved": "https://registry.npmjs.org/@vue/apollo-composable/-/apollo-composable-4.0.0-beta.1.tgz", @@ -7696,6 +7913,342 @@ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" }, + "node_modules/esbuild": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -15748,6 +16301,20 @@ "rimraf": "bin.js" } }, + "node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -17664,6 +18231,54 @@ "extsprintf": "^1.2.0" } }, + "node_modules/vite": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", + "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", + "dependencies": { + "esbuild": "^0.15.9", + "postcss": "^8.4.18", + "resolve": "^1.22.1", + "rollup": "^2.79.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, "node_modules/vue": { "version": "3.2.30", "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.30.tgz", @@ -17914,6 +18529,21 @@ "node": ">=4.0.0" } }, + "node_modules/vue-tsc": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-0.40.13.tgz", + "integrity": "sha512-xzuN3g5PnKfJcNrLv4+mAjteMd5wLm5fRhW0034OfNJZY4WhB07vhngea/XeGn7wNYt16r7syonzvW/54dcNiA==", + "dependencies": { + "@volar/vue-language-core": "0.40.13", + "@volar/vue-typescript": "0.40.13" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, "node_modules/vue-vimeo-player": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vue-vimeo-player/-/vue-vimeo-player-1.1.2.tgz", @@ -20157,6 +20787,18 @@ "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" }, + "@esbuild/android-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "optional": true + }, "@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -21155,6 +21797,24 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" }, + "@rollup/plugin-graphql": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-graphql/-/plugin-graphql-1.1.0.tgz", + "integrity": "sha512-X+H6oFlprDlnO3D0UiEytdW97AMphPXO0C7KunS7i/rBXIGQRQVDU5WKTXnBu2tfyYbjCTtfhXMSGI0i885PNg==", + "requires": { + "@rollup/pluginutils": "^4.0.0", + "graphql-tag": "^2.2.2" + } + }, + "@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "requires": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + } + }, "@sentry-internal/tracing": { "version": "7.45.0", "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.45.0.tgz", @@ -21871,6 +22531,158 @@ "weakmap-polyfill": "2.0.4" } }, + "@vitejs/plugin-vue": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz", + "integrity": "sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==", + "requires": {} + }, + "@volar/code-gen": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/@volar/code-gen/-/code-gen-0.40.13.tgz", + "integrity": "sha512-4gShBWuMce868OVvgyA1cU5WxHbjfEme18Tw6uVMfweZCF5fB2KECG0iPrA9D54vHk3FeHarODNwgIaaFfUBlA==", + "requires": { + "@volar/source-map": "0.40.13" + } + }, + "@volar/source-map": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-0.40.13.tgz", + "integrity": "sha512-dbdkAB2Nxb0wLjAY5O64o3ywVWlAGONnBIoKAkXSf6qkGZM+nJxcizsoiI66K+RHQG0XqlyvjDizfnTxr+6PWg==", + "requires": { + "@vue/reactivity": "3.2.38" + }, + "dependencies": { + "@vue/reactivity": { + "version": "3.2.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.38.tgz", + "integrity": "sha512-6L4myYcH9HG2M25co7/BSo0skKFHpAN8PhkNPM4xRVkyGl1K5M3Jx4rp5bsYhvYze2K4+l+pioN4e6ZwFLUVtw==", + "requires": { + "@vue/shared": "3.2.38" + } + }, + "@vue/shared": { + "version": "3.2.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.38.tgz", + "integrity": "sha512-dTyhTIRmGXBjxJE+skC8tTWCGLCVc4wQgRRLt8+O9p5ewBAjoBwtCAkLPrtToSr1xltoe3st21Pv953aOZ7alg==" + } + } + }, + "@volar/typescript-faster": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/@volar/typescript-faster/-/typescript-faster-0.40.13.tgz", + "integrity": "sha512-uy+TlcFkKoNlKEnxA4x5acxdxLyVDIXGSc8cYDNXpPKjBKXrQaetzCzlO3kVBqu1VLMxKNGJMTKn35mo+ILQmw==", + "requires": { + "semver": "^7.3.7" + }, + "dependencies": { + "semver": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", + "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@volar/vue-language-core": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/@volar/vue-language-core/-/vue-language-core-0.40.13.tgz", + "integrity": "sha512-QkCb8msi2KUitTdM6Y4kAb7/ZlEvuLcbBFOC2PLBlFuoZwyxvSP7c/dBGmKGtJlEvMX0LdCyrg5V2aBYxD38/Q==", + "requires": { + "@volar/code-gen": "0.40.13", + "@volar/source-map": "0.40.13", + "@vue/compiler-core": "^3.2.38", + "@vue/compiler-dom": "^3.2.38", + "@vue/compiler-sfc": "^3.2.38", + "@vue/reactivity": "^3.2.38", + "@vue/shared": "^3.2.38" + }, + "dependencies": { + "@vue/compiler-core": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", + "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==", + "requires": { + "@babel/parser": "^7.16.4", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "source-map": "^0.6.1" + } + }, + "@vue/compiler-dom": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz", + "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==", + "requires": { + "@vue/compiler-core": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "@vue/compiler-sfc": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz", + "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==", + "requires": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.47", + "@vue/compiler-dom": "3.2.47", + "@vue/compiler-ssr": "3.2.47", + "@vue/reactivity-transform": "3.2.47", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7", + "postcss": "^8.1.10", + "source-map": "^0.6.1" + } + }, + "@vue/compiler-ssr": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz", + "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==", + "requires": { + "@vue/compiler-dom": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "@vue/reactivity": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.47.tgz", + "integrity": "sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==", + "requires": { + "@vue/shared": "3.2.47" + } + }, + "@vue/reactivity-transform": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz", + "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==", + "requires": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.47", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7" + } + }, + "@vue/shared": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz", + "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==" + } + } + }, + "@volar/vue-typescript": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/@volar/vue-typescript/-/vue-typescript-0.40.13.tgz", + "integrity": "sha512-o7bNztwjs8JmbQjVkrnbZUOfm7q4B8ZYssETISN1tRaBdun6cfNqgpkvDYd+VUBh1O4CdksvN+5BUNnwAz4oCQ==", + "requires": { + "@volar/code-gen": "0.40.13", + "@volar/typescript-faster": "0.40.13", + "@volar/vue-language-core": "0.40.13" + } + }, "@vue/apollo-composable": { "version": "4.0.0-beta.1", "resolved": "https://registry.npmjs.org/@vue/apollo-composable/-/apollo-composable-4.0.0-beta.1.tgz", @@ -24433,6 +25245,155 @@ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" }, + "esbuild": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "requires": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" + } + }, + "esbuild-android-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", + "optional": true + }, + "esbuild-linux-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", + "optional": true + }, + "esbuild-linux-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", + "optional": true + }, + "esbuild-windows-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", + "optional": true + }, + "esbuild-windows-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", + "optional": true + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -30282,6 +31243,14 @@ "glob": "^7.1.3" } }, + "rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "requires": { + "fsevents": "~2.3.2" + } + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -31688,6 +32657,18 @@ "extsprintf": "^1.2.0" } }, + "vite": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", + "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", + "requires": { + "esbuild": "^0.15.9", + "fsevents": "~2.3.2", + "postcss": "^8.4.18", + "resolve": "^1.22.1", + "rollup": "^2.79.1" + } + }, "vue": { "version": "3.2.30", "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.30.tgz", @@ -31868,6 +32849,15 @@ } } }, + "vue-tsc": { + "version": "0.40.13", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-0.40.13.tgz", + "integrity": "sha512-xzuN3g5PnKfJcNrLv4+mAjteMd5wLm5fRhW0034OfNJZY4WhB07vhngea/XeGn7wNYt16r7syonzvW/54dcNiA==", + "requires": { + "@volar/vue-language-core": "0.40.13", + "@volar/vue-typescript": "0.40.13" + } + }, "vue-vimeo-player": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vue-vimeo-player/-/vue-vimeo-player-1.1.2.tgz", diff --git a/client/package.json b/client/package.json index e52daa9d..e451fcd1 100644 --- a/client/package.json +++ b/client/package.json @@ -9,12 +9,11 @@ }, "private": true, "scripts": { - "dev": "webpack serve --progress --config build/webpack.dev.conf.js", - "analyze": "webpack --profile --json --config build/webpack.dev.conf.js > dist/stats.json && webpack-bundle-analyzer dist/stats.json", "start": ". ../server/.env && npm run dev", "lint": "eslint --ext .js,.vue,.ts src", "fix-lint": "eslint --ext .js,.vue,.ts --fix src", - "build": "node build/build.js", + "build": "vite build", + "dev": "vite", "open:cypress:e2e": "npm run cypress:e2e:open", "open:cypress:frontend": "npm run cypress:frontend:open", "test:cypress:e2e": "npm run cypress:e2e:test", @@ -43,6 +42,7 @@ "@graphql-tools/jest-transform": "^1.2.2", "@graphql-tools/mock": "^8.6.5", "@graphql-tools/schema": "^8.3.7", + "@rollup/plugin-graphql": "^1.1.0", "@sentry/vue": "^7.45.0", "@sentry/webpack-plugin": "^1.20.0", "@tiptap/core": "^2.0.0-beta.174", @@ -54,6 +54,7 @@ "@tiptap/vue-3": "^2.0.0-beta.90", "@typescript-eslint/eslint-plugin": "^5.10.0", "@typescript-eslint/parser": "^5.10.0", + "@vitejs/plugin-vue": "^3.0.3", "@vue/apollo-composable": "^4.0.0-beta.1", "@vue/apollo-option": "^4.0.0-alpha.16", "@vue/compat": "3.2.30", @@ -107,17 +108,19 @@ "semver": "^5.3.0", "shelljs": "^0.8.5", "survey-knockout": "^1.9.41", + "typescript": "^4.6.4", "ts-loader": "^8.3.0", - "typescript": "^4.5.4", "uploadcare-widget": "^3.6.0", "url-loader": "^4.1.1", "vee-validate": "^4.5.10", + "vite": "^3.1.0", "vue": "3.2.30", "vue-loader": "^16.8.3", "vue-matomo": "^4.2.0", "vue-router": "^4.0.14", "vue-scrollto": "^2.20.0", "vue-style-loader": "^3.0.1", + "vue-tsc": "^0.40.4", "vue-vimeo-player": "^1.1.2", "vuex": "4.0.1", "webpack": "^5.67.0", diff --git a/client/src/App.vue b/client/src/App.vue index 6dd5919a..0db09cc5 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -21,52 +21,52 @@ diff --git a/client/src/components/instruments/FilterEntry.vue b/client/src/components/instruments/FilterEntry.vue index f287b64e..2df9610a 100644 --- a/client/src/components/instruments/FilterEntry.vue +++ b/client/src/components/instruments/FilterEntry.vue @@ -23,7 +23,7 @@ import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFilter.gql'; import { defineAsyncComponent } from 'vue'; const ChevronRight = defineAsyncComponent(() => - import(/* webpackChunkName: "icons" */ '@/components/icons/ChevronRight') + import('@/components/icons/ChevronRight.vue') ); export default { @@ -105,7 +105,7 @@ export default { diff --git a/client/src/components/portfolio/EditProject.vue b/client/src/components/portfolio/EditProject.vue index 739d2ffb..738b1bb8 100644 --- a/client/src/components/portfolio/EditProject.vue +++ b/client/src/components/portfolio/EditProject.vue @@ -7,7 +7,7 @@ diff --git a/client/src/components/profile/GroupList.vue b/client/src/components/profile/GroupList.vue index b6843d20..a1464c6e 100644 --- a/client/src/components/profile/GroupList.vue +++ b/client/src/components/profile/GroupList.vue @@ -93,7 +93,7 @@ diff --git a/client/src/components/profile/ModuleActivity.vue b/client/src/components/profile/ModuleActivity.vue index 83d9f656..07ab1655 100644 --- a/client/src/components/profile/ModuleActivity.vue +++ b/client/src/components/profile/ModuleActivity.vue @@ -59,8 +59,8 @@ diff --git a/client/src/components/toggle-menu/ToggleEditing.vue b/client/src/components/toggle-menu/ToggleEditing.vue index 40d4f0e1..8a6413dd 100644 --- a/client/src/components/toggle-menu/ToggleEditing.vue +++ b/client/src/components/toggle-menu/ToggleEditing.vue @@ -8,7 +8,7 @@ + + diff --git a/client/src/components/ui/file-upload/SimpleFileUpload.vue b/client/src/components/ui/file-upload/SimpleFileUpload.vue index d3240e3b..1e686d2f 100644 --- a/client/src/components/ui/file-upload/SimpleFileUpload.vue +++ b/client/src/components/ui/file-upload/SimpleFileUpload.vue @@ -53,7 +53,7 @@ const clickUploadCare = () => { diff --git a/client/src/pages/me/myTeam.vue b/client/src/pages/me/myTeam.vue index a5774a86..8fc2f548 100644 --- a/client/src/pages/me/myTeam.vue +++ b/client/src/pages/me/myTeam.vue @@ -41,7 +41,7 @@ diff --git a/client/src/pages/module/moduleSettings.vue b/client/src/pages/module/moduleSettings.vue index f6cc83bb..bee93148 100644 --- a/client/src/pages/module/moduleSettings.vue +++ b/client/src/pages/module/moduleSettings.vue @@ -28,7 +28,7 @@ diff --git a/client/src/pages/rooms/newRoom.vue b/client/src/pages/rooms/newRoom.vue index 9b4259ed..d06f8c73 100644 --- a/client/src/pages/rooms/newRoom.vue +++ b/client/src/pages/rooms/newRoom.vue @@ -6,7 +6,7 @@ diff --git a/client/src/pages/rooms/room.vue b/client/src/pages/rooms/room.vue index 7c92012a..74295cd6 100644 --- a/client/src/pages/rooms/room.vue +++ b/client/src/pages/rooms/room.vue @@ -57,8 +57,8 @@ import ROOM_ENTRIES_QUERY from 'gql/queries/roomEntriesQuery.gql'; import room from '@/mixins/room'; import me from '@/mixins/me'; -import BackLink from '@/components/BackLink'; -import RoomVisibilityWidget from '@/components/rooms/RoomVisibilityWidget'; +import BackLink from '@/components/BackLink.vue'; +import RoomVisibilityWidget from '@/components/rooms/RoomVisibilityWidget.vue'; import { ROOMS_PAGE } from '@/router/room.names'; export default { @@ -104,5 +104,5 @@ export default { diff --git a/client/src/pages/rooms/rooms.vue b/client/src/pages/rooms/rooms.vue index 517b7bd3..ce58ece0 100644 --- a/client/src/pages/rooms/rooms.vue +++ b/client/src/pages/rooms/rooms.vue @@ -27,7 +27,7 @@ import ME_QUERY from 'gql/queries/meQuery.gql'; import RoomWidget from '@/components/rooms/RoomWidget.vue'; import AddRoom from '@/components/rooms/AddRoom.vue'; -import RoomsOnboarding from '@/components/rooms/RoomsOnboarding'; +import RoomsOnboarding from '@/components/rooms/RoomsOnboarding.vue'; export default { components: { @@ -79,7 +79,7 @@ export default { diff --git a/client/src/pages/topic-page.vue b/client/src/pages/topic-page.vue index 50a2d769..648e6735 100644 --- a/client/src/pages/topic-page.vue +++ b/client/src/pages/topic-page.vue @@ -49,13 +49,13 @@ import ModuleTeaser from '@/components/modules/ModuleTeaser.vue'; import { defineAsyncComponent } from 'vue'; import TOPIC_QUERY from '@/graphql/gql/queries/topicQuery.gql'; import me from '@/mixins/me'; -import TopicNavigation from '@/components/book-navigation/TopicNavigation'; +import TopicNavigation from '@/components/book-navigation/TopicNavigation.vue'; import UPDATE_LAST_TOPIC_MUTATION from '@/graphql/gql/mutations/updateLastTopic.gql'; import ME_QUERY from '@/graphql/gql/queries/meQuery.gql'; -const PlayIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Play')); -const BulbIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/BulbIcon')); +const PlayIcon = defineAsyncComponent(() => import('@/components/icons/Play.vue')); +const BulbIcon = defineAsyncComponent(() => import('@/components/icons/BulbIcon.vue')); export default { mixins: [me], diff --git a/client/src/router/auth.routes.js b/client/src/router/auth.routes.js index 3d3d35a5..ff7af719 100644 --- a/client/src/router/auth.routes.js +++ b/client/src/router/auth.routes.js @@ -1,9 +1,9 @@ import { LICENSE_ACTIVATION } from '@/router/auth.names'; -const hello = () => import(/* webpackChunkName: "auth" */ '@/pages/hello'); -const betaLogin = () => import(/* webpackChunkName: "auth" */ '@/pages/beta-login'); -const loginError = () => import(/* webpackChunkName: "auth" */ '@/pages/login-error'); -const licenseActivation = () => import(/* webpackChunkName: "auth" */ '@/pages/license-activation'); +const hello = () => import('@/pages/hello.vue'); +const betaLogin = () => import('@/pages/beta-login.vue'); +const loginError = () => import('@/pages/login-error.vue'); +const licenseActivation = () => import('@/pages/license-activation.vue'); export default [ { diff --git a/client/src/router/index.js b/client/src/router/index.js index c98d6e81..89ebe2cb 100644 --- a/client/src/router/index.js +++ b/client/src/router/index.js @@ -11,25 +11,25 @@ import { store } from '@/store'; import { LAYOUT_SIMPLE } from '@/router/core.constants'; import { EMAIL_NOT_VERIFIED_STATE, NO_VALID_LICENSE_STATE, SUCCESS_STATE } from './oauth.names'; -import start from '@/pages/start'; +import start from '@/pages/start.vue'; import { PAGE_LOAD_TIMEOUT } from '@/consts/navigation.consts'; import { matomoTrackPageView } from '@/helpers/matomo-client'; -const instrument = () => import(/* webpackChunkName: "instruments" */ '@/pages/instrument'); -const instrumentOverview = () => import(/* webpackChunkName: "instruments" */ '@/pages/instrumentOverview'); +const instrument = () => import('@/pages/instrument.vue'); +const instrumentOverview = () => import('@/pages/instrumentOverview.vue'); -const article = () => import(/* webpackChunkName: "news" */ '@/pages/article'); -const news = () => import(/* webpackChunkName: "news" */ '@/pages/news'); +const article = () => import('@/pages/article.vue'); +const news = () => import('@/pages/news.vue'); -const surveyPage = () => import(/* webpackChunkName: "survey" */ '@/pages/survey'); +const surveyPage = () => import('@/pages/survey.vue'); -const styleGuidePage = () => import('@/pages/styleguide'); -const joinClass = () => import('@/pages/joinClass'); +const styleGuidePage = () => import('@/pages/styleguide.vue'); +const joinClass = () => import('@/pages/joinClass.vue'); -const topic = () => import('@/pages/topic-page'); +const topic = () => import('@/pages/topic-page.vue'); -const p404 = () => import('@/pages/p404'); -const submission = () => import('@/pages/studentSubmission'); +const p404 = () => import('@/pages/p404.vue'); +const submission = () => import('@/pages/studentSubmission.vue'); const postLoginRedirectUrlKey = 'postLoginRedirectionUrl'; diff --git a/client/src/router/me.routes.js b/client/src/router/me.routes.js index f25f2760..91ebe565 100644 --- a/client/src/router/me.routes.js +++ b/client/src/router/me.routes.js @@ -1,17 +1,17 @@ import { CREATE_TEAM, JOIN_TEAM, MY_TEAM, SHOW_SCHOOL_CLASS_CODE, SHOW_TEAM_CODE } from './me.names'; import { LAYOUT_SIMPLE } from '@/router/core.constants'; -const profilePage = () => import(/* webpackChunkName: "profile" */ '@/pages/profile'); -const profile = () => import(/* webpackChunkName: "profile" */ '@/components/profile/Profile'); -const myClass = () => import(/* webpackChunkName: "profile" */ '@/pages/myClass'); -const activity = () => import(/* webpackChunkName: "profile" */ '@/pages/activity'); -const oldClasses = () => import(/* webpackChunkName: "profile" */ '@/pages/oldClasses'); -const createClass = () => import(/* webpackChunkName: "profile" */ '@/pages/createClass'); -const showSchoolClassCode = () => import(/* webpackChunkName: "profile" */ '@/pages/me/showSchoolClassCode'); -const showTeamCode = () => import(/* webpackChunkName: "profile" */ '@/pages/me/showTeamCode'); -const myTeam = () => import(/* webpackChunkName: "profile" */ '@/pages/me/myTeam'); -const joinTeam = () => import(/* webpackChunkName: "profile" */ '@/pages/me/joinTeam'); -const createTeam = () => import(/* webpackChunkName: "profile" */ '@/pages/me/createTeam'); +const profilePage = () => import('@/pages/profile.vue'); +const profile = () => import('@/components/profile/Profile.vue'); +const myClass = () => import('@/pages/myClass.vue'); +const activity = () => import('@/pages/activity.vue'); +const oldClasses = () => import('@/pages/oldClasses.vue'); +const createClass = () => import('@/pages/createClass.vue'); +const showSchoolClassCode = () => import('@/pages/me/showSchoolClassCode.vue'); +const showTeamCode = () => import('@/pages/me/showTeamCode.vue'); +const myTeam = () => import('@/pages/me/myTeam.vue'); +const joinTeam = () => import('@/pages/me/joinTeam.vue'); +const createTeam = () => import('@/pages/me/createTeam.vue'); export default [ { diff --git a/client/src/router/module.routes.js b/client/src/router/module.routes.js index 8090a8eb..f19c6b5b 100644 --- a/client/src/router/module.routes.js +++ b/client/src/router/module.routes.js @@ -10,16 +10,16 @@ import { VISIBILITY_PAGE, } from '@/router/module.names'; import { LAYOUT_SIMPLE } from '@/router/core.constants'; -import createContentBlock from '@/pages/createContentBlock'; -import editContentBlock from '@/pages/editContentBlock'; +import createContentBlock from '@/pages/createContentBlock.vue'; +import editContentBlock from '@/pages/editContentBlock.vue'; -const moduleBase = () => import(/* webpackChunkName: "modules" */ '@/pages/module/module-base'); -const module = () => import(/* webpackChunkName: "modules" */ '@/pages/module/module'); -const submissions = () => import(/* webpackChunkName: "modules" */ '@/pages/submissions'); -const moduleVisibility = () => import(/* webpackChunkName: "modules" */ '@/pages/module/moduleVisibility'); -const settingsPage = () => import(/* webpackChunkName: "modules" */ '@/pages/module/moduleSettings'); -const snapshots = () => import(/* webpackChunkName: "modules" */ '@/pages/snapshot/snapshots'); -const snapshot = () => import(/* webpackChunkName: "modules" */ '@/pages/snapshot/snapshot'); +const moduleBase = () => import('@/pages/module/module-base.vue'); +const module = () => import('@/pages/module/module.vue'); +const submissions = () => import('@/pages/submissions.vue'); +const moduleVisibility = () => import('@/pages/module/moduleVisibility.vue'); +const settingsPage = () => import('@/pages/module/moduleSettings.vue'); +const snapshots = () => import('@/pages/snapshot/snapshots.vue'); +const snapshot = () => import('@/pages/snapshot/snapshot.vue'); const contentBlockLocator = () => import(/* webpackChunkName: "modules" */ '@/pages/contentBlockLocator.vue'); const contentBlockFormMeta = { diff --git a/client/src/router/portfolio.routes.js b/client/src/router/portfolio.routes.js index 80f38a22..18f583c4 100644 --- a/client/src/router/portfolio.routes.js +++ b/client/src/router/portfolio.routes.js @@ -1,10 +1,10 @@ import { NEW_PROJECT_PAGE, PROJECTS_PAGE } from '@/router/portfolio.names'; import flavorValues from '@/helpers/app-flavor'; -const portfolio = () => import(/* webpackChunkName: "portfolio" */ '@/pages/portfolio/portfolio'); -const project = () => import(/* webpackChunkName: "portfolio" */ '@/pages/portfolio/project'); -const newProject = () => import(/* webpackChunkName: "portfolio" */ '@/pages/portfolio/newProject'); -const editProject = () => import(/* webpackChunkName: "portfolio" */ '@/pages/portfolio/editProject'); +const portfolio = () => import('@/pages/portfolio/portfolio.vue'); +const project = () => import('@/pages/portfolio/project.vue'); +const newProject = () => import('@/pages/portfolio/newProject.vue'); +const editProject = () => import('@/pages/portfolio/editProject.vue'); const portfolioRoutes = [ { path: '/portfolio', name: PROJECTS_PAGE, component: portfolio, meta: { hideFooter: true, matomoUrl: '/portfolio/' } }, diff --git a/client/src/router/room.routes.js b/client/src/router/room.routes.js deleted file mode 100644 index d436610d..00000000 --- a/client/src/router/room.routes.js +++ /dev/null @@ -1,44 +0,0 @@ -import { - NEW_ROOM_PAGE, - ROOMS_PAGE, - ADD_ROOM_ENTRY_PAGE, - ROOM_PAGE, - UPDATE_ROOM_ENTRY_PAGE, - ADD_MODULE_ROOM_ENTRY_PAGE, - MODULE_ROOM_PAGE, -} from '@/router/room.names'; - -const rooms = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/rooms'); -const newRoom = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/newRoom'); -const editRoom = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/editRoom'); -const room = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/room'); -const newRoomEntry = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/newRoomEntry'); -const editRoomEntry = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/editRoomEntry'); -const moduleRoom = () => import(/* webpackChunkName: "rooms" */ '@/pages/module/moduleRoom'); - -function matomoRoomWithSlugCallback(route) { - return `/room/${route.params.slug}/`; -} - -export default [ - { path: '/rooms', name: ROOMS_PAGE, component: rooms, meta: { filter: true, hideFooter: true, matomoUrl: '/room/' }}, - { path: '/new-room/', name: NEW_ROOM_PAGE, component: newRoom }, - { path: '/edit-room/:id', name: 'edit-room', component: editRoom, props: true }, - { path: '/room/:slug', name: ROOM_PAGE, component: room, props: true, meta: { matomoUrlCallback: matomoRoomWithSlugCallback }}, - { path: '/room/:slug/add', name: ADD_ROOM_ENTRY_PAGE, component: newRoomEntry, props: true, meta: { matomoUrlCallback: matomoRoomWithSlugCallback }}, - { path: '/room/:slug/edit/:entrySlug', name: UPDATE_ROOM_ENTRY_PAGE, component: editRoomEntry, meta: { matomoUrlCallback: matomoRoomWithSlugCallback }}, - { - path: '/module-room/:slug', - name: MODULE_ROOM_PAGE, - component: moduleRoom, - props: true, - meta: { layout: 'fullScreen', matomoUrlCallback: matomoRoomWithSlugCallback }, - }, - { - path: '/module-room/:slug/add', - name: ADD_MODULE_ROOM_ENTRY_PAGE, - component: newRoomEntry, - props: (route) => ({ slug: route.params.slug, isModule: true }), - meta: { matomoUrlCallback: matomoRoomWithSlugCallback }, - }, -]; diff --git a/client/src/router/room.routes.ts b/client/src/router/room.routes.ts new file mode 100644 index 00000000..edb1576c --- /dev/null +++ b/client/src/router/room.routes.ts @@ -0,0 +1,61 @@ +import { + NEW_ROOM_PAGE, + ROOMS_PAGE, + ADD_ROOM_ENTRY_PAGE, + ROOM_PAGE, + UPDATE_ROOM_ENTRY_PAGE, + ADD_MODULE_ROOM_ENTRY_PAGE, + MODULE_ROOM_PAGE, +} from '@/router/room.names'; + +const rooms = () => import('@/pages/rooms/rooms.vue'); +const newRoom = () => import('@/pages/rooms/newRoom.vue'); +const editRoom = () => import('@/pages/rooms/editRoom.vue'); +const room = () => import('@/pages/rooms/room.vue'); +const newRoomEntry = () => import('@/pages/rooms/newRoomEntry.vue'); +const editRoomEntry = () => import('@/pages/rooms/editRoomEntry.vue'); +const moduleRoom = () => import('@/pages/module/moduleRoom.vue'); + +function matomoRoomWithSlugCallback(route) { + return `/room/${route.params.slug}/`; +} + +export default [ + { path: '/rooms', name: ROOMS_PAGE, component: rooms, meta: { filter: true, hideFooter: true, matomoUrl: '/room/' } }, + { path: '/new-room/', name: NEW_ROOM_PAGE, component: newRoom }, + { path: '/edit-room/:id', name: 'edit-room', component: editRoom, props: true }, + { + path: '/room/:slug', + name: ROOM_PAGE, + component: room, + props: true, + meta: { matomoUrlCallback: matomoRoomWithSlugCallback }, + }, + { + path: '/room/:slug/add', + name: ADD_ROOM_ENTRY_PAGE, + component: newRoomEntry, + props: true, + meta: { matomoUrlCallback: matomoRoomWithSlugCallback }, + }, + { + path: '/room/:slug/edit/:entrySlug', + name: UPDATE_ROOM_ENTRY_PAGE, + component: editRoomEntry, + meta: { matomoUrlCallback: matomoRoomWithSlugCallback }, + }, + { + path: '/module-room/:slug', + name: MODULE_ROOM_PAGE, + component: moduleRoom, + props: true, + meta: { layout: 'fullScreen', matomoUrlCallback: matomoRoomWithSlugCallback }, + }, + { + path: '/module-room/:slug/add', + name: ADD_MODULE_ROOM_ENTRY_PAGE, + component: newRoomEntry, + props: (route) => ({ slug: route.params.slug, isModule: true }), + meta: { matomoUrlCallback: matomoRoomWithSlugCallback }, + }, +]; diff --git a/client/src/setup/plugins.ts b/client/src/setup/plugins.ts index 63183f4a..daca8250 100644 --- a/client/src/setup/plugins.ts +++ b/client/src/setup/plugins.ts @@ -18,11 +18,11 @@ const apolloProvider = createApolloProvider({ defaultClient: privateApolloClient, }); const registerPlugins = (app: any) => { - if (process.env.SENTRY_DSN) { + if (import.meta.env.SENTRY_DSN) { Sentry.init({ app, - dsn: process.env.SENTRY_DSN, - environment: process.env.SENTRY_ENVIRONMENT || 'localhost', + dsn: import.meta.env.SENTRY_DSN, + environment: import.meta.env.SENTRY_ENVIRONMENT || 'localhost', }); } app.use(store); @@ -32,12 +32,12 @@ const registerPlugins = (app: any) => { app.use(apolloProvider); app.use(router); app.use(flavorPlugin); - if (process.env.MATOMO_HOST) { + if (import.meta.env.MATOMO_HOST) { // MS-628: we use VueMatomo "only" to setup the Matomo tracker // we will not use any of the provided functions app.use(VueMatomo, { - host: process.env.MATOMO_HOST, - siteId: process.env.MATOMO_SITE_ID, + host: import.meta.env.MATOMO_HOST, + siteId: import.meta.env.MATOMO_SITE_ID, enableHeartBeatTimer: true, // we don't want the default vue-matomo router behaviour router: null, diff --git a/client/src/setup/router.ts b/client/src/setup/router.ts index 7c7b67d9..db6f2fc4 100644 --- a/client/src/setup/router.ts +++ b/client/src/setup/router.ts @@ -32,8 +32,8 @@ const setupRouteGuards = () => { // logger.$log.debug('navigation guard called', to, from); if (to.path === '/logout') { await publicApolloClient.resetStore(); - if (process.env.LOGOUT_REDIRECT_URL) { - location.replace(`https://sso.hep-verlag.ch/logout?return_to=${process.env.LOGOUT_REDIRECT_URL}`); + if (import.meta.env.LOGOUT_REDIRECT_URL) { + location.replace(`https://sso.hep-verlag.ch/logout?return_to=${import.meta.env.LOGOUT_REDIRECT_URL}`); next(false); return; } else { diff --git a/client/src/shims-vue.d.ts b/client/src/shims-vue.d.ts index 4ee6a24c..3e07610a 100644 --- a/client/src/shims-vue.d.ts +++ b/client/src/shims-vue.d.ts @@ -4,13 +4,23 @@ // export default Vue; // } -// for Vue 3 -declare module '*.vue' { - import type { DefineComponent } from 'vue'; - const component: DefineComponent<{}, {}, any>; - export default component; +// for Vue 3 compat +declare module 'vue' { + import { CompatVue } from '@vue/runtime-dom'; + const Vue: CompatVue; + export default Vue; + export * from '@vue/runtime-dom'; + const { configureCompat } = Vue; + export { configureCompat }; } +// for Vue 3 +// declare module '*.vue' { +// import type { DefineComponent } from 'vue'; +// const component: DefineComponent<{}, {}, any>; +// export default component; +// } + // ugly hack to make types for those two packages declare module 'vue-vimeo-player' { const plugin: any; diff --git a/client/src/styles/_default-layout.scss b/client/src/styles/_default-layout.scss index 20c5e84f..a29c2c5b 100644 --- a/client/src/styles/_default-layout.scss +++ b/client/src/styles/_default-layout.scss @@ -1,4 +1,4 @@ -@import '~styles/helpers'; +@import 'styles/helpers'; .layout { $footer-height: 287px; diff --git a/client/src/styles/_room.scss b/client/src/styles/_room.scss index 0703fe92..95330bb0 100644 --- a/client/src/styles/_room.scss +++ b/client/src/styles/_room.scss @@ -1,4 +1,4 @@ -@import '~styles/helpers'; +@import 'styles/helpers'; .room { display: grid; diff --git a/client/src/styles/_student-submission.scss b/client/src/styles/_student-submission.scss index ca98234e..118268e7 100644 --- a/client/src/styles/_student-submission.scss +++ b/client/src/styles/_student-submission.scss @@ -1,4 +1,4 @@ -@import '~styles/helpers'; +@import 'styles/helpers'; .student-submission-row { display: grid; diff --git a/client/tests/unit/checkbox.spec.js b/client/tests/unit/checkbox.spec.js index 018cb8f8..ff56d72a 100644 --- a/client/tests/unit/checkbox.spec.js +++ b/client/tests/unit/checkbox.spec.js @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils'; -import Checkbox from '@/components/ui/BaseInput'; +import Checkbox from '@/components/ui/BaseInput.vue'; describe('Checkbox.vue', () => { it('should display the provided props', async () => { diff --git a/client/tests/unit/class-selection-widget.spec.js b/client/tests/unit/class-selection-widget.spec.js index 1da46f69..4bb6ede6 100644 --- a/client/tests/unit/class-selection-widget.spec.js +++ b/client/tests/unit/class-selection-widget.spec.js @@ -8,7 +8,7 @@ import MY_SCHOOL_CLASS_QUERY from '@/graphql/gql/queries/mySchoolClass.gql'; import DELETE_MODULE_NODES from '@/graphql/gql/local/mutations/deleteModuleNodes.gql'; import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql'; -import ClassSelectionWidget from '@/components/school-class/ClassSelectionWidget'; +import ClassSelectionWidget from '@/components/school-class/ClassSelectionWidget.vue'; // https://dev.to/n_tepluhina/testing-vue-apollo-2020-edition-2l2p diff --git a/client/tests/unit/comment-input.spec.js b/client/tests/unit/comment-input.spec.js index 860788da..28b180ad 100644 --- a/client/tests/unit/comment-input.spec.js +++ b/client/tests/unit/comment-input.spec.js @@ -1,5 +1,5 @@ import { shallowMount } from '@vue/test-utils'; -import CommentInput from '@/components/rooms/CommentInput'; +import CommentInput from '@/components/rooms/CommentInput.vue'; describe('CommentInput.vue', () => { it('should clear input after submit', async () => { diff --git a/client/tests/unit/module-navigation.spec.js b/client/tests/unit/module-navigation.spec.js index ee4f5d58..6b611c9b 100644 --- a/client/tests/unit/module-navigation.spec.js +++ b/client/tests/unit/module-navigation.spec.js @@ -1,5 +1,5 @@ import { shallowMount } from '@vue/test-utils'; -import ModuleNavigation from '@/components/modules/ModuleNavigation'; +import ModuleNavigation from '@/components/modules/ModuleNavigation.vue'; describe('ModuleNavigation.vue', () => { it('should flatten an array', () => { diff --git a/client/tests/unit/text-form.spec.js b/client/tests/unit/text-form.spec.js index fd5517bd..4b3b9a11 100644 --- a/client/tests/unit/text-form.spec.js +++ b/client/tests/unit/text-form.spec.js @@ -1,5 +1,5 @@ import { shallowMount } from '@vue/test-utils'; -import TextForm from '@/components/content-forms/TextForm'; +import TextForm from '@/components/content-forms/TextForm.vue'; describe('TextForm.vue', () => { it('should emit user input and its index', async () => { diff --git a/client/tests/unit/toggle.spec.js b/client/tests/unit/toggle.spec.js index 955550a6..fa5c3d8a 100644 --- a/client/tests/unit/toggle.spec.js +++ b/client/tests/unit/toggle.spec.js @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils'; -import Toggle from '@/components/ui/Toggle'; +import Toggle from '@/components/ui/Toggle.vue'; describe('Toggle.vue', () => { it.skip('should toggle the input value from true to false and back', async () => { diff --git a/client/vite.config.ts b/client/vite.config.ts new file mode 100644 index 00000000..027fbb62 --- /dev/null +++ b/client/vite.config.ts @@ -0,0 +1,89 @@ +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; +import gql from '@rollup/plugin-graphql'; +import path from 'path'; + +const getFlavorConfig = () => { + switch (process.env.APP_FLAVOR) { + case 'my-kv': + return require('./config/prod-my-kv.env.js').default; + case 'my-dhf': + return require('./config/prod-dhf.env.js').default; + case 'my-dha': + return require('./config/prod-dha.env.js').default; + } + return {}; +}; + +function resolve(dir: string) { + return path.join(__dirname, dir); +} + +const define = { + 'import.meta.env.HEP_URL': JSON.stringify(process.env.HEP_URL), + 'import.meta.env.MATOMO_HOST': JSON.stringify(process.env.MATOMO_HOST), + 'import.meta.env.MATOMO_SITE_ID': JSON.stringify(process.env.MATOMO_SITE_ID), + 'import.meta.env.LOGOUT_REDIRECT_URL': JSON.stringify(process.env.LOGOUT_REDIRECT_URL), + 'import.meta.env.VUE_APP_FLAVOR': JSON.stringify(process.env.APP_FLAVOR), + 'import.meta.env.SENTRY_DSN': JSON.stringify(process.env.SENTRY_JAVASCRIPT_DSN), + 'import.meta.env.SENTRY_ENVIRONMENT': JSON.stringify(process.env.SENTRY_ENV), + /* + * ENV variables used in JS code need to be stringyfied, as they will be replaced (in place) in the code, + * and JS needs quotes around strings + * see https://cli.vuejs.org/guide/mode-and-env.html#using-env-variables-in-client-side-code + */ + 'import.meta.env.VUE_APP_ENABLE_SPELLCHECK': !!process.env.TASKBASE_BASEURL, +}; + +const flavorConfig = getFlavorConfig(); + +const htmlPlugin = () => { + return { + name: 'html-transform', + transformIndexHtml(html: string) { + return html + .replace(/_APP_TITLE_/, flavorConfig.VUE_APP_TITLE || 'mySkillbox') + .replace(/_FAVICON_16_/, flavorConfig.VUE_APP_FAVICON_16 || '/static/favicon-16x16.png') + .replace(/_FAVICON_32_/, flavorConfig.VUE_APP_FAVICON_32 || '/static/favicon-32x32.png'); + }, + }; +}; + +// https://vitejs.dev/config/ +export default defineConfig({ + build: { + assetsDir: 'static', + }, + css: { + preprocessorOptions: { + scss: { + additionalData: process.env.THEME ? `@import "styles/themes/_${process.env.THEME}.scss";` : '', + }, + }, + devSourcemap: true, + }, + resolve: { + alias: { + '@': resolve('./src'), + styles: resolve('./src/styles'), + gql: resolve('./src/graphql/gql'), + vue: '@vue/compat' + }, + }, + server: { + port: 8080, + hmr: { + clientPort: 8080, + }, + }, + plugins: [gql(), vue({ + template: { + compilerOptions: { + compatConfig: { + MODE: 2 + } + } + } + }), htmlPlugin()], + define, +});