Merge branch 'feat/instance-customization' into 'main'

Feat/instance customization

See merge request geovisio/website!48
This commit is contained in:
Jean Andreani
2023-05-11 11:27:16 +00:00
29 changed files with 948 additions and 52 deletions

View File

@@ -20,7 +20,8 @@ module.exports = {
],
rules: {
'vue/require-default-prop': 'off',
'prettier/prettier': 'error'
'prettier/prettier': 'error',
'@typescript-eslint/no-namespace': 'off'
// override/add rules settings here, such as:
// 'vue/no-unused-vars': 'error'
}

20
cypress.config.ts Normal file
View File

@@ -0,0 +1,20 @@
import { defineConfig } from 'cypress'
export default defineConfig({
component: {
devServer: {
framework: 'vue',
bundler: 'vite'
}
},
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
baseUrl: 'http://localhost:5173',
supportFile: 'src/tests/cypress/support/e2e.{js,jsx,ts,tsx}',
specPattern: 'src/tests/cypress/**/*.cy.{js,jsx,ts,tsx}',
fixturesFolder: 'src/tests/cypress/fixtures'
}
})

View File

@@ -44,6 +44,7 @@
"@vue/eslint-config-typescript": "^11.0.0",
"@vue/test-utils": "^2.2.4",
"@vue/tsconfig": "^0.1.3",
"cypress": "^12.12.0",
"eslint": "^8.29.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-vue": "^9.8.0",

View File

@@ -1,8 +1,12 @@
<script setup lang="ts">
import Header from '@/components/Header.vue'
import { RouterView } from 'vue-router'
import { useMeta } from 'vue-meta'
import { useI18n } from 'vue-i18n'
import authConfig from './composables/auth'
const { authConf } = authConfig()
const { t } = useI18n()
useMeta({
title: t('general.title'),
og: {
@@ -20,6 +24,11 @@ useMeta({
<metainfo>
<template v-slot:title="{ content }">{{ content }}</template>
</metainfo>
<Header
v-if="authConf.user_profile"
:auth-enabled="authConf.enabled"
:user-profile-url="authConf.user_profile.url"
/>
<RouterView />
</template>
<style scoped></style>

View File

@@ -39,7 +39,7 @@
path="/partager-des-photos"
/>
</div>
<div class="item-with-sub">
<div v-if="authEnabled" class="item-with-sub">
<Link
type="external"
icon="bi bi-person-circle"
@@ -49,7 +49,7 @@
/>
<i v-if="isLogged" class="chevron bi bi-chevron-up"></i>
<div v-if="isLogged" class="sub-nav-block">
<div class="logged-link">
<div v-if="userProfileUrl" class="logged-link">
<Link
path="mon-compte"
:text="$t('general.header.account_text')"
@@ -85,6 +85,11 @@ import BetaText from '@/components/BetaText.vue'
const { cookies } = useCookies()
const { t } = useI18n()
const route = useRoute()
defineProps({
authEnabled: { type: Boolean, default: true },
userProfileUrl: { type: String, default: null }
})
let menuIsClosed = ref<boolean>(true)
function toggleMenu(): void {

View File

@@ -45,7 +45,7 @@ import Button from '@/components/Button.vue'
import { computed, ref } from 'vue'
let uploadIsCopied = ref<boolean>(false)
const props = defineProps({
defineProps({
textUpload: { type: String, default: '' },
textInstall: { type: String, default: '' }
})

23
src/composables/auth.ts Normal file
View File

@@ -0,0 +1,23 @@
import axios from 'axios'
import { onMounted, ref } from 'vue'
interface UserProfileInterface {
url?: string
}
interface AuthConfigInterface {
enabled?: boolean
user_profile?: UserProfileInterface
}
export default function authConfig() {
const authConf = ref<AuthConfigInterface>({})
async function getConfig(): Promise<object> {
const { data } = await axios.get(
`${import.meta.env.VITE_API_URL}api/configuration`
)
return data.auth
}
onMounted(async () => (authConf.value = await getConfig()))
return { authConf }
}

View File

@@ -17,6 +17,7 @@ axios.defaults.baseURL = import.meta.env.VITE_API_URL
const i18n = createI18n({
locale: 'fr',
fallbackLocale: 'fr',
warnHtmlMessage: false,
globalInjection: true,
legacy: false,
messages: {
@@ -24,11 +25,7 @@ const i18n = createI18n({
}
})
globalCookiesConfig({
expireTimes: '7d',
path: '/',
domain: import.meta.env.VITE_API_URL,
secure: true,
sameSite: 'None'
expireTimes: '7d'
})
const app = createApp(App)

View File

@@ -0,0 +1,23 @@
describe('In the home page', () => {
it('click to full and reduce the size of the image', () => {
cy.visit('/')
cy.get('.gvs-mini-buttons button:nth-child(2)').click()
cy.get('.gvs-mini-buttons button:nth-child(2)').click()
})
it('type an address in the search and go to the localization in the map', () => {
cy.visit('/')
cy.fixture('home').then((homeData) => {
cy.get('.mapboxgl-ctrl-geocoder--input').type(homeData.addressToSearch)
cy.contains(homeData.textAddressToSelect).click()
})
})
it('click on the link in the header to go to the upload page', () => {
cy.visit('/')
cy.fixture('home').then((homeData) => {
cy.contains(homeData.textLinkUpload).click()
cy.url().should('include', '/partager-des-photos')
})
})
})
export {}

View File

@@ -0,0 +1,8 @@
describe('In the login page', () => {
it('type in the form to login', () => {
cy.visit('https://geovisio-backend-dev.osc-fr1.scalingo.io/api/auth/login')
cy.get('#password').type('coucouc')
})
})
export {}

View File

@@ -0,0 +1,23 @@
describe('In the upload page', () => {
it('go to the login page', () => {
cy.visit('partager-des-photos')
cy.fixture('upload').then((uploadData) => {
cy.contains(uploadData.textButtonUpload).click()
})
})
it('go to the login page', () => {
cy.visit('partager-des-photos')
cy.fixture('upload').then((uploadData) => {
cy.contains(uploadData.textButtonUpload).click()
})
})
it('go to the cli page', () => {
cy.visit('partager-des-photos')
cy.fixture('upload').then((uploadData) => {
cy.contains(uploadData.textButtonCli).click()
cy.url().should('include', '/partager-des-photos')
})
})
})
export {}

View File

@@ -0,0 +1,5 @@
{
"addressToSearch": "97 boulevard Voltaire 75011 paris",
"textAddressToSelect": "Boulevard Voltaire, Quartier de la Folie-Méricourt, Paris 11e Arrondissement, Paris, Île-de-France, France métropolitaine, 75011, France",
"textLinkUpload": "Partager des photos"
}

View File

@@ -0,0 +1,4 @@
{
"textButtonUpload": "Créer un compte",
"textButtonCli": "Accéder à l'outil"
}

View File

@@ -0,0 +1,38 @@
/// <reference types="cypress" />
// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
export {}

View File

@@ -0,0 +1,20 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
// Alternatively you can use CommonJS syntax:
import commands from '/commands'

View File

@@ -1,8 +1,8 @@
import { it, describe, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import BetaText from '../BetaText.vue'
import BetaText from '../../../components/BetaText.vue'
import { createI18n } from 'vue-i18n'
import fr from '../../locales/fr.json'
import fr from '../../../locales/fr.json'
const i18n = createI18n({
locale: 'fr',

View File

@@ -1,8 +1,8 @@
import { vi, it, beforeEach, describe, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import { createI18n } from 'vue-i18n'
import fr from '../../locales/fr.json'
import Header from '../Header.vue'
import fr from '../../../locales/fr.json'
import Header from '../../../components/Header.vue'
vi.mock('vue-router')
const i18n = createI18n({
@@ -62,6 +62,10 @@ describe('Template', () => {
})
it('should render the component with good wording keys', async () => {
const wrapper = shallowMount(Header, {
props: {
authEnabled: true,
userProfileUrl: 'profil'
},
global: {
plugins: [i18n],
mocks: {
@@ -79,6 +83,10 @@ describe('Template', () => {
})
it('should render the component logout link', async () => {
const wrapper = shallowMount(Header, {
props: {
authEnabled: true,
userProfileUrl: 'profil'
},
global: {
plugins: [i18n],
mocks: {

View File

@@ -1,6 +1,6 @@
import { test, describe, vi, expect } from 'vitest'
import { mount, shallowMount } from '@vue/test-utils'
import Link from '../Link.vue'
import Link from '../../../components/Link.vue'
import { useI18n } from 'vue-i18n'
vi.mock('vue-i18n')

View File

@@ -1,9 +1,9 @@
import { it, describe, expect, vi } from 'vitest'
import { shallowMount, mount } from '@vue/test-utils'
import Terminal from '../Terminal.vue'
import Button from '../Button.vue'
import Terminal from '../../../components/Terminal.vue'
import Button from '../../../components/Button.vue'
import { createI18n } from 'vue-i18n'
import fr from '../../locales/fr.json'
import fr from '../../../locales/fr.json'
const i18n = createI18n({
locale: 'fr',

View File

@@ -1,6 +1,6 @@
import { it, describe, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import MyAccountView from '../MyAccountView.vue'
import MyAccountView from '../../../views/MyAccountView.vue'
describe('Template', () => {
it('should render the view with the iframe', async () => {

View File

@@ -1,8 +1,8 @@
import { it, describe, expect } from 'vitest'
import { it, describe, expect, vi } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import UploadView from '../UploadView.vue'
import UploadView from '../../../views/UploadView.vue'
import { createI18n } from 'vue-i18n'
import fr from '../../locales/fr.json'
import fr from '../../../locales/fr.json'
const i18n = createI18n({
locale: 'fr',
@@ -21,7 +21,10 @@ describe('Template', () => {
global: {
plugins: [i18n],
mocks: {
$t: (msg) => msg
$t: (msg) => msg,
authConf: {
enabled: true
}
}
}
})
@@ -32,4 +35,20 @@ describe('Template', () => {
expect(wrapper.html()).contains('look="button"')
expect(wrapper.html()).contains('type="external"')
})
it('should render the view without the button link', async () => {
import.meta.env.VITE_API_URL = 'api-url/'
const wrapper = shallowMount(UploadView, {
global: {
plugins: [i18n],
mocks: {
$t: (msg) => msg,
authConf: {
enabled: false
}
}
}
})
console.log(wrapper.html())
expect(wrapper.html()).not.toContain('pages.upload.sub_title')
})
})

View File

@@ -4,7 +4,6 @@
type="text/css"
href="https://cdn.jsdelivr.net/npm/geovisio@develop/build/index.css"
/>
<Header />
<main class="entry-page">
<section id="viewer" class="entry-viewer">
<div v-if="mapIsLoaded" class="entry-report-button">
@@ -23,7 +22,6 @@ import axios from 'axios'
import { useI18n } from 'vue-i18n'
import { onMounted, computed, ref } from 'vue'
import GeoVisio from 'geovisio'
import Header from '@/components/Header.vue'
import Button from '@/components/Button.vue'
const { t } = useI18n()

View File

@@ -1,12 +1,10 @@
<template>
<Header />
<main class="entry-page">
<iframe :src="myAccountUrl" class="iframe"></iframe>
</main>
</template>
<script setup lang="ts">
import Header from '@/components/Header.vue'
import { onMounted, computed } from 'vue'
import { useCookies } from 'vue3-cookies'
import { useRoute } from 'vue-router'

View File

@@ -1,5 +1,4 @@
<template>
<Header />
<main class="entry-page">
<section id="sec-1" class="section-upload section-color">
<div class="wrapper-upload">
@@ -14,7 +13,7 @@
</div>
</div>
<p class="upload-text" v-html="$t('pages.upload.description')" />
<div v-if="!isLogged" class="wrapper-account">
<div v-if="!isLogged && authConf.enabled" class="wrapper-account">
<h4 class="account-subtitle">
{{ $t('pages.upload.sub_title') }}
</h4>
@@ -88,14 +87,15 @@
<script lang="ts" setup>
import Link from '@/components/Link.vue'
import Header from '@/components/Header.vue'
import Terminal from '@/components/Terminal.vue'
import { useCookies } from 'vue3-cookies'
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute } from 'vue-router'
import authConfig from '../composables/auth'
const { cookies } = useCookies()
const { t } = useI18n()
const { authConf } = authConfig()
const route = useRoute()
let hrefSection = ref<string>('#sec-2')

View File

@@ -1,7 +1,7 @@
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue", "src/locales/*.json"],
"exclude": ["src/**/__tests__/*"],
"exclude": ["src/tests/unit/*"],
"compilerOptions": {
"composite": true,
"baseUrl": ".",

View File

@@ -6,6 +6,7 @@
"cypress.config.*",
"playwright.config.*"
],
"extensions": [".js", ".jsx", ".ts", ".tsx"],
"compilerOptions": {
"types": ["node", "vite/client"]
}

View File

@@ -8,9 +8,9 @@ export default defineConfig({
server: {
host: true,
port: 5173,
strictPort: true,
hmr: {
port: 9000,
overlay: false
port: 9000
}
},
base: '/',

735
yarn.lock

File diff suppressed because it is too large Load Diff