forked from Ivasoft/geovisio-website
Compare commits
10 Commits
tech-add-t
...
57-filter-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cec383e424 | ||
|
|
7e20788591 | ||
|
|
390343916e | ||
|
|
c768b714b9 | ||
|
|
bf0bc4d91c | ||
|
|
5d292b186c | ||
|
|
93e434ecf9 | ||
|
|
721bafbd3e | ||
|
|
127550a19f | ||
|
|
85abc46038 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -90,6 +90,7 @@ sw.*
|
||||
*.swp
|
||||
|
||||
# Cypress generated screen and videos files
|
||||
cypress/downloads/*
|
||||
cypress/screenshot/
|
||||
cypress/videos/
|
||||
*.cy.ts.mp4
|
||||
@@ -8,9 +8,10 @@ variables:
|
||||
DOCKER_BUILDKIT: 1 # use buildkit for better performance
|
||||
DOCKER_DRIVER: overlay2 # better docker driver to avoid copying too many files on each run
|
||||
GITLAB_REGISTRY: registry.gitlab.com # We use docker.io for official images and gitlab's registry to store temporary images
|
||||
IMAGE_NAME: geovisio/api
|
||||
IMAGE_NAME: geovisio/website
|
||||
CI_IMAGE_CACHE: $GITLAB_REGISTRY/$IMAGE_NAME:build_cache
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
DOCKER_TLS_CERTDIR: ''
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
|
||||
before_script:
|
||||
## chmod is unfortunately currently mandatory : https://github.com/nodejs/docker-node/issues/661
|
||||
@@ -22,28 +23,29 @@ cache:
|
||||
|
||||
install:
|
||||
stage: Install
|
||||
image: node:18.16.0
|
||||
image: node:18.16.1
|
||||
script:
|
||||
- yarn install
|
||||
- ls node_modules/.bin/cypress
|
||||
|
||||
test:unit:
|
||||
stage: Test
|
||||
image: node:18.16.0
|
||||
image: node:18.16.1
|
||||
script:
|
||||
- yarn test:unit
|
||||
coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
|
||||
|
||||
test:e2e:
|
||||
stage: Test
|
||||
image: cypress/browsers:node-18.16.0-chrome-113.0.5672.92-1-ff-113.0-edge-113.0.1774.35-1
|
||||
image: node:18.16.1-alpine
|
||||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- yarn install
|
||||
- ./node_modules/.bin/cypress install
|
||||
- echo "VITE_API_URL=https://geovisio-proxy-dev.osc-fr1.scalingo.io/" > .env
|
||||
- echo "VITE_ENV=dev" >> .env
|
||||
- PORT=5173 yarn start &
|
||||
- yarn test:e2e
|
||||
- apk add --update --no-cache docker-cli docker-cli-compose git
|
||||
- PROJECT_DIR=$PWD docker compose -f cypress/docker-compose-geovisio.yml -f cypress/docker-compose-gitlab-override.yml run --rm e2e
|
||||
after_script:
|
||||
- PROJECT_DIR=$PWD docker compose -f cypress/docker-compose-geovisio.yml -f cypress/docker-compose-gitlab-override.yml logs web || true
|
||||
- PROJECT_DIR=$PWD docker compose -f cypress/docker-compose-geovisio.yml -f cypress/docker-compose-gitlab-override.yml down || true
|
||||
coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
|
||||
artifacts:
|
||||
when: always
|
||||
@@ -54,7 +56,7 @@ test:e2e:
|
||||
|
||||
deploy:
|
||||
stage: Deploy
|
||||
image: node:18.16.0
|
||||
image: node:18.16.1
|
||||
cache:
|
||||
paths:
|
||||
- node_modules
|
||||
@@ -74,7 +76,7 @@ deploy:develop:
|
||||
stage: Deploy
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
- docker:dind
|
||||
before_script:
|
||||
# login to the gitlab docker registry to use the cache and to publish
|
||||
- echo $CI_DEPLOY_PASSWORD | docker login -u $CI_DEPLOY_USER --password-stdin $GITLAB_REGISTRY
|
||||
@@ -106,7 +108,7 @@ deploy:latest:
|
||||
stage: Deploy
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
- docker:dind
|
||||
before_script:
|
||||
# login to the gitlab docker registry to use the cache and to publish
|
||||
- echo $CI_DEPLOY_PASSWORD | docker login -u $CI_DEPLOY_USER --password-stdin $GITLAB_REGISTRY
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#- Build image
|
||||
#-
|
||||
|
||||
FROM node:18.16.0-alpine AS build
|
||||
FROM node:18.16.1-alpine AS build
|
||||
|
||||
WORKDIR /opt/geovisio
|
||||
|
||||
|
||||
@@ -12,6 +12,6 @@ export default defineConfig({
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
baseUrl: 'http://localhost:5173'
|
||||
baseUrl: 'http://localhost:5173/'
|
||||
}
|
||||
})
|
||||
|
||||
3
cypress.env.json
Normal file
3
cypress.env.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"api_url": "http://localhost:5000/"
|
||||
}
|
||||
79
cypress/docker-compose-geovisio.yml
Normal file
79
cypress/docker-compose-geovisio.yml
Normal file
@@ -0,0 +1,79 @@
|
||||
services:
|
||||
api:
|
||||
image: geovisio/api:develop
|
||||
command: api
|
||||
restart: always
|
||||
ports:
|
||||
- 5000:5000
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
auth:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
DB_URL: postgres://gvs:gvspwd@db/geovisio
|
||||
PICTURE_PROCESS_THREADS_LIMIT: 2
|
||||
PICTURE_PROCESS_DERIVATES_STRATEGY: ON_DEMAND
|
||||
API_FORCE_AUTH_ON_UPLOAD: 'true'
|
||||
OAUTH_CLIENT_ID: geovisio
|
||||
OAUTH_CLIENT_SECRET: what_a_secret
|
||||
OAUTH_OIDC_URL: http://localhost:8183/realms/geovisio
|
||||
OAUTH_PROVIDER: oidc
|
||||
FLASK_SECRET_KEY: a_very_secret_key_never_to_be_used_in_production
|
||||
healthcheck:
|
||||
test: python -c "import requests; requests.get('http://localhost:5000/api').raise_for_status()"
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
extra_hosts:
|
||||
- 'localhost:host-gateway'
|
||||
|
||||
networks:
|
||||
db: {}
|
||||
geovisio:
|
||||
aliases:
|
||||
- api.localtest.me
|
||||
|
||||
db:
|
||||
image: postgis/postgis:13-3.2
|
||||
environment:
|
||||
- POSTGRES_USER=gvs
|
||||
- POSTGRES_PASSWORD=gvspwd
|
||||
- POSTGRES_DB=geovisio
|
||||
healthcheck:
|
||||
test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
db: {}
|
||||
|
||||
auth:
|
||||
command: start-dev --import-realm
|
||||
environment:
|
||||
GEOVISIO_BASE_URL: http://localhost:5000
|
||||
GEOVISIO_CLIENT_SECRET: what_a_secret
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: password
|
||||
KEYCLOAK_FRONTEND_URL: http://localhost:5000/api/auth/login
|
||||
KC_HTTP_PORT: 8183
|
||||
ports:
|
||||
- '8183:8183'
|
||||
healthcheck:
|
||||
test: curl --fail http://localhost:8183/realms/geovisio
|
||||
timeout: 5s
|
||||
interval: 2s
|
||||
retries: 20
|
||||
start_period: 15s
|
||||
image: quay.io/keycloak/keycloak:20.0.1
|
||||
volumes:
|
||||
- ./keycloak-realm.json:/opt/keycloak/data/import/geovisio_realm.json
|
||||
|
||||
networks:
|
||||
geovisio:
|
||||
aliases:
|
||||
- keycloak.localtest.me
|
||||
|
||||
networks:
|
||||
db: {}
|
||||
geovisio: {}
|
||||
55
cypress/docker-compose-gitlab-override.yml
Normal file
55
cypress/docker-compose-gitlab-override.yml
Normal file
@@ -0,0 +1,55 @@
|
||||
# Docker-compose used in gitlab-ci to run a container having access to all the other containers
|
||||
services:
|
||||
web:
|
||||
image: node:18.16.1-alpine
|
||||
volumes:
|
||||
- $PROJECT_DIR:/src
|
||||
working_dir: /src
|
||||
command: >
|
||||
sh -c "apk add --update --no-cache curl && yarn install && yarn start"
|
||||
environment:
|
||||
PORT: 5173
|
||||
VITE_API_URL: http://api.localtest.me:5000
|
||||
VITE_ENV: dev
|
||||
depends_on:
|
||||
api:
|
||||
condition: service_healthy
|
||||
auth:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- 5173:5173
|
||||
healthcheck:
|
||||
test: curl --fail http://0.0.0.0:5173
|
||||
timeout: 10s
|
||||
interval: 3s
|
||||
retries: 20
|
||||
start_period: 15s
|
||||
networks:
|
||||
geovisio:
|
||||
aliases:
|
||||
- front.localtest.me
|
||||
e2e:
|
||||
image: cypress/included:cypress-12.17.3-node-18.16.1-chrome-114.0.5735.133-1-ff-114.0.2-edge-114.0.1823.51-1
|
||||
volumes:
|
||||
- $PROJECT_DIR:/src
|
||||
working_dir: /src
|
||||
environment:
|
||||
- CYPRESS_baseUrl=http://front.localtest.me:5173/
|
||||
- CYPRESS_api_url=http://api.localtest.me:5000/
|
||||
- LANG=fr
|
||||
command: sleep 2 && yarn add --dev cypress && ./node_modules/.bin/cypress install && yarn test:e2e
|
||||
depends_on:
|
||||
web:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
geovisio: {}
|
||||
|
||||
api:
|
||||
environment:
|
||||
OAUTH_OIDC_URL: http://keycloak.localtest.me:8183/realms/geovisio
|
||||
FLASK_SESSION_COOKIE_DOMAIN: localtest.me
|
||||
|
||||
auth:
|
||||
environment:
|
||||
GEOVISIO_BASE_URL: http://api.localtest.me:5000
|
||||
KEYCLOAK_FRONTEND_URL: http://api.localtest.me:5000/api/auth/login
|
||||
29
cypress/e2e/contribute.cy.ts
Normal file
29
cypress/e2e/contribute.cy.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
describe('In the contribute page', () => {
|
||||
it('go to the login page', () => {
|
||||
cy.visit('/pourquoi-contribuer')
|
||||
cy.get('.upload-text').scrollIntoView()
|
||||
cy.fixture('contribute').then((contributeData: contributeInterface) => {
|
||||
cy.contains(contributeData.textButtonContribute).click()
|
||||
})
|
||||
})
|
||||
it('go to the doc pages', () => {
|
||||
cy.visit('pourquoi-contribuer')
|
||||
cy.fixture('contribute').then((contributeData: contributeInterface) => {
|
||||
cy.get('.upload-text').scrollIntoView()
|
||||
cy.contains(contributeData.textButtonDocPython).click()
|
||||
cy.contains(contributeData.textButtonCli).click()
|
||||
cy.contains(contributeData.textButtonDocCli).click()
|
||||
cy.contains(contributeData.textButtonTiles).click()
|
||||
cy.contains(contributeData.textButtonDoc).click()
|
||||
})
|
||||
})
|
||||
})
|
||||
interface contributeInterface {
|
||||
textButtonContribute: string
|
||||
textButtonDocPython: string
|
||||
textButtonCli: string
|
||||
textButtonDocCli: string
|
||||
textButtonTiles: string
|
||||
textButtonDoc: string
|
||||
}
|
||||
export {}
|
||||
16
cypress/e2e/home.cy.ts
Normal file
16
cypress/e2e/home.cy.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
describe('In the home page', () => {
|
||||
it('click on the link in the footer to go to Panoramax.fr', () => {
|
||||
cy.visit('/')
|
||||
cy.fixture('home').then((homeData) => {
|
||||
cy.contains(homeData.textLinkPanoramax).click()
|
||||
})
|
||||
})
|
||||
it('click on the link in the footer to go to Gitlab', () => {
|
||||
cy.visit('/')
|
||||
cy.fixture('home').then((homeData) => {
|
||||
cy.contains(homeData.textLinkGitlab).click()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
export {}
|
||||
@@ -1,7 +1,25 @@
|
||||
describe('In the login page', () => {
|
||||
it('type in the form to login', () => {
|
||||
cy.visit(`${Cypress.env('api_url')}api/auth/login`)
|
||||
cy.get('#username').type('Elysee')
|
||||
cy.get('#password').type('my password')
|
||||
cy.contains('Sign In').click()
|
||||
cy.visit('/')
|
||||
})
|
||||
it('go to the register form and create an account', () => {
|
||||
cy.visit(`${Cypress.env('api_url')}api/auth/login`)
|
||||
cy.fixture('login').then((loginData) => {
|
||||
cy.contains(loginData.textLinkRegister).click()
|
||||
cy.get('#firstName').type('Tom')
|
||||
cy.get('#lastName').type('Tom')
|
||||
cy.get('#email').type('test@test123.com')
|
||||
cy.get('#username').type('Elysee12445')
|
||||
cy.get('#password').type('my password1')
|
||||
cy.get('#password-confirm').type('my password1')
|
||||
cy.get('form').submit()
|
||||
cy.visit('/')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
export {}
|
||||
|
||||
9
cypress/e2e/tsconfig.json
Normal file
9
cypress/e2e/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": ["reflect-metadata", "jest", "cypress"],
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"sourceMap": true
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
32
cypress/e2e/upload.cy.ts
Normal file
32
cypress/e2e/upload.cy.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
describe('In the login page', () => {
|
||||
it('login and go to the upload page to upload images', () => {
|
||||
cy.visit(`${Cypress.env('api_url')}api/auth/login`)
|
||||
cy.get('#username').type('Elysee')
|
||||
cy.get('#password').type('my password')
|
||||
cy.fixture('upload').then((uploadData: uploadInterface) => {
|
||||
cy.contains(uploadData.textLinkLogin).click()
|
||||
cy.visit('/envoyer')
|
||||
cy.get('.edit-button').click()
|
||||
cy.get('#upload-title').clear()
|
||||
cy.get('#upload-title').type(uploadData.textTitle)
|
||||
cy.contains(uploadData.textButtonTitle).click()
|
||||
cy.contains(uploadData.textButtonUpload).click()
|
||||
})
|
||||
cy.get('.input-file').selectFile(
|
||||
[
|
||||
'/src/cypress/fixtures/images/image1.jpg',
|
||||
'/src/cypress/fixtures/images/image2.jpg',
|
||||
'/src/cypress/fixtures/images/image3.jpg'
|
||||
],
|
||||
{ force: true }
|
||||
)
|
||||
})
|
||||
})
|
||||
interface uploadInterface {
|
||||
textLinkLogin: string
|
||||
textLinkUpload: string
|
||||
textButtonUpload: string
|
||||
textTitle: string
|
||||
textButtonTitle: string
|
||||
}
|
||||
export {}
|
||||
8
cypress/fixtures/contribute.json
Normal file
8
cypress/fixtures/contribute.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"textButtonContribute": "Partager des images",
|
||||
"textButtonDocCli": "Voir la documentation",
|
||||
"textButtonDoc": "Retrouvez sa documentation ici",
|
||||
"textButtonDocPython": "de python (au moins la version 3.8)",
|
||||
"textButtonCli": "L'outil en ligne de commande",
|
||||
"textButtonTiles": "de tuiles vectorielles"
|
||||
}
|
||||
5
cypress/fixtures/home.json
Normal file
5
cypress/fixtures/home.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"textLinkContribute": "Pourquoi contribuer ?",
|
||||
"textLinkPanoramax": "Découvrir Panoramax",
|
||||
"textLinkGitlab": "Voir le code"
|
||||
}
|
||||
BIN
cypress/fixtures/images/image1.jpg
Normal file
BIN
cypress/fixtures/images/image1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
cypress/fixtures/images/image2.jpg
Normal file
BIN
cypress/fixtures/images/image2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
BIN
cypress/fixtures/images/image3.jpg
Normal file
BIN
cypress/fixtures/images/image3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
4
cypress/fixtures/login.json
Normal file
4
cypress/fixtures/login.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"textLinkRegister": "Register",
|
||||
"textLinkLogin": "Sign In"
|
||||
}
|
||||
7
cypress/fixtures/upload.json
Normal file
7
cypress/fixtures/upload.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"textLinkLogin": "Sign In",
|
||||
"textLinkUpload": "Mes photos",
|
||||
"textTitle": "My title",
|
||||
"textButtonTitle": "Valider",
|
||||
"textButtonUpload": "Glissez vos images ici ou cliquez sur"
|
||||
}
|
||||
1987
cypress/keycloak-realm.json
Normal file
1987
cypress/keycloak-realm.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
"name": "geovisio-website",
|
||||
"version": "2.3.0",
|
||||
"engines": {
|
||||
"node": "18.16.0"
|
||||
"node": "18.16.1"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -42,6 +42,7 @@
|
||||
"devDependencies": {
|
||||
"@pinia/testing": "^0.1.2",
|
||||
"@rushstack/eslint-patch": "^1.1.4",
|
||||
"@types/jest": "^29.5.4",
|
||||
"@types/jsdom": "^20.0.1",
|
||||
"@types/node": "^18.11.18",
|
||||
"@typescript-eslint/eslint-plugin": "^5.46.0",
|
||||
@@ -52,12 +53,13 @@
|
||||
"@vue/eslint-config-typescript": "^11.0.0",
|
||||
"@vue/test-utils": "^2.2.4",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"cypress": "^12.12.0",
|
||||
"cypress": "^13.1.0",
|
||||
"eslint": "^8.29.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.5",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-vue": "^9.8.0",
|
||||
"jest": "^29.6.4",
|
||||
"jsdom": "^20.0.3",
|
||||
"less": "^4.2.0",
|
||||
"less-loader": "^11.1.3",
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
export function createLink(href: string, text: string): string {
|
||||
return `<a href='mailto:signalement.ign@panoramax.fr${href}' target='_blank' title='${text}' class='gvs-btn gvs-widget-bg gvs-btn-large' style='font-size: 1.6em;display: block'><i class="bi bi-exclamation-triangle"></i></a>`
|
||||
}
|
||||
export function createSequenceLink(href: string, title: string): string {
|
||||
return `<a href='${href}' title='${title}' class='gvs-btn gvs-widget-bg gvs-btn-large' style='font-size: 1.6em;display: block; position: relative'>
|
||||
<i class="bi bi-images"></i>
|
||||
</a>`
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
>
|
||||
<div class="wrapper-input">
|
||||
<Input
|
||||
id="upload-title"
|
||||
:text="text || ''"
|
||||
:placeholder="$t('pages.upload.edit_placeholder_input')"
|
||||
@input="changeTextValue"
|
||||
|
||||
@@ -128,7 +128,6 @@ onClickOutside(list, () => closeModal())
|
||||
function closeModal(): void {
|
||||
menuIsClosed.value = true
|
||||
}
|
||||
|
||||
function toggleMenu(): void {
|
||||
menuIsClosed.value = !menuIsClosed.value
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const titleImg = computed<string>(() =>
|
||||
props.disabled ? t('general.header.contribute_text') : ''
|
||||
props.disabled ? t('general.header.about_text') : ''
|
||||
)
|
||||
function triggerButton() {
|
||||
if (props.disabled) return
|
||||
|
||||
@@ -3,13 +3,18 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import type { ViewerInterface, MapInterface } from '@/views/interfaces/common'
|
||||
import { getIgnTiles } from '@/utils/mapAndViewer'
|
||||
import axios from 'axios'
|
||||
import { onMounted, onUnmounted, ref, computed } from 'vue'
|
||||
import { useSequenceStore } from '@/store/sequence'
|
||||
import { Viewer, StandaloneMap } from 'geovisio'
|
||||
import { getIgnTiles } from '@/utils/mapAndViewer'
|
||||
import { createUrlLink } from '@/utils'
|
||||
import { createLink } from '@/components-viewer/reportLink'
|
||||
import { createLink, createSequenceLink } from '@/components-viewer/reportLink'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { hasASessionCookieDecoded } from '@/utils/auth'
|
||||
import type { ViewerInterface, MapInterface } from '@/views/interfaces/common'
|
||||
|
||||
const sequenceStore = useSequenceStore()
|
||||
const { t } = useI18n()
|
||||
let mapIsLoaded = ref<boolean>(false)
|
||||
let viewer = ref()
|
||||
@@ -20,119 +25,152 @@ const props = defineProps({
|
||||
bbox: { type: Array, default: null },
|
||||
userId: { type: String, default: '' }
|
||||
})
|
||||
const isLogged = computed((): boolean => {
|
||||
const cookie = hasASessionCookieDecoded()
|
||||
return !!(cookie && cookie.account)
|
||||
})
|
||||
const userName = computed((): string => {
|
||||
const cookie = hasASessionCookieDecoded()
|
||||
if (cookie && cookie.account) return cookie.account.name
|
||||
return ''
|
||||
})
|
||||
defineExpose({
|
||||
viewer
|
||||
})
|
||||
onMounted(async () => {
|
||||
const tiles = import.meta.env.VITE_TILES
|
||||
async function getSequenceId(imgId: string): Promise<{
|
||||
sequenceId: string
|
||||
username: string
|
||||
}> {
|
||||
const { data } = await axios.get(`api/search?ids=${imgId}`)
|
||||
return {
|
||||
sequenceId: data.features[0].collection,
|
||||
username: data.features[0].properties['geovisio:producer']
|
||||
}
|
||||
}
|
||||
function createViewerButton(link: HTMLDivElement): void {
|
||||
viewer.value.addEventListener(
|
||||
'picture-loaded',
|
||||
async (e: { detail: { picId: string } }): Promise<void> => {
|
||||
const sequenceInformation = await getSequenceId(e.detail.picId)
|
||||
let href: string
|
||||
if (isLogged.value && sequenceInformation.username === userName.value) {
|
||||
href = `${window.location.origin}/sequence/${sequenceInformation.sequenceId}?currentPic=${e.detail.picId}`
|
||||
link.innerHTML = createSequenceLink(
|
||||
href,
|
||||
t('pages.home.sequence_title')
|
||||
)
|
||||
sequenceStore.addSequence(e.detail.picId)
|
||||
} else {
|
||||
href = t('pages.home.report_mail', {
|
||||
picId: e.detail.picId,
|
||||
link: createUrlLink(e.detail.picId)
|
||||
})
|
||||
link.innerHTML = createLink(href, t('pages.home.report_button_text'))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
async function setupViewerMap(tiles: string): Promise<void> {
|
||||
const maxZoom = import.meta.env.VITE_MAX_ZOOM
|
||||
const zoom = import.meta.env.VITE_ZOOM
|
||||
const center = import.meta.env.VITE_CENTER
|
||||
let paramsViewer: ViewerInterface
|
||||
let paramsMap: MapInterface
|
||||
|
||||
try {
|
||||
if (props.geovisioViewer) {
|
||||
paramsViewer = { map: { startWide: true } }
|
||||
if (center && center !== '') {
|
||||
const centerMap = center.split(',').map((el: string) => parseInt(el))
|
||||
paramsViewer = {
|
||||
map: {
|
||||
...paramsViewer.map,
|
||||
center: centerMap
|
||||
}
|
||||
}
|
||||
let paramsViewer: ViewerInterface = { map: { startWide: true } }
|
||||
if (center && center !== '') {
|
||||
const centerMap = center.split(',').map((el: string) => parseInt(el))
|
||||
paramsViewer = {
|
||||
map: {
|
||||
...paramsViewer.map,
|
||||
center: centerMap
|
||||
}
|
||||
if (zoom && zoom !== '') {
|
||||
paramsViewer = {
|
||||
map: {
|
||||
...paramsViewer.map,
|
||||
zoom: parseFloat(zoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxZoom && maxZoom !== '') {
|
||||
paramsViewer = {
|
||||
map: {
|
||||
...paramsViewer.map,
|
||||
maxZoom: parseInt(maxZoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tiles) {
|
||||
const style = tiles.includes('wxs.ign.fr') ? await getIgnTiles() : tiles
|
||||
paramsViewer = {
|
||||
map: {
|
||||
...paramsViewer.map,
|
||||
style
|
||||
}
|
||||
}
|
||||
}
|
||||
if (props.fetchOptions) {
|
||||
paramsViewer = {
|
||||
...paramsViewer,
|
||||
...props.fetchOptions
|
||||
}
|
||||
}
|
||||
const reportLink = document.createElement('div')
|
||||
reportLink.className = 'gvs-group gvs-group-large gvs-group-btnpanel'
|
||||
viewer.value = new Viewer(
|
||||
'viewer', // Div ID
|
||||
`${import.meta.env.VITE_API_URL}/api/search`,
|
||||
{
|
||||
...paramsViewer,
|
||||
widgets: { customWidget: reportLink }
|
||||
}
|
||||
)
|
||||
if (viewer.value && viewer.value.addEventListener) {
|
||||
viewer.value.addEventListener(
|
||||
'picture-loaded',
|
||||
async (e: { detail: { picId: string } }): Promise<void> => {
|
||||
const href = t('pages.home.report_mail', {
|
||||
picId: e.detail.picId,
|
||||
link: createUrlLink(e.detail.picId)
|
||||
})
|
||||
reportLink.innerHTML = createLink(
|
||||
href,
|
||||
t('pages.home.report_button_text')
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
paramsMap = { minZoom: 7 }
|
||||
if (tiles) {
|
||||
const style = tiles.includes('wxs.ign.fr') ? await getIgnTiles() : tiles
|
||||
paramsMap = {
|
||||
...paramsMap,
|
||||
style
|
||||
}
|
||||
}
|
||||
const bbox = [props.bbox[0], props.bbox[1], props.bbox[2], props.bbox[3]]
|
||||
viewer.value = new StandaloneMap(
|
||||
'viewer', // Div ID
|
||||
`${import.meta.env.VITE_API_URL}/api/search`,
|
||||
{
|
||||
...paramsMap,
|
||||
bounds: bbox,
|
||||
zoom: 14
|
||||
}
|
||||
)
|
||||
viewer.value.addEventListener('ready', () => {
|
||||
viewer.value.setFilters({ user: props.userId }, true)
|
||||
viewer.value.fitBounds(bbox, {
|
||||
padding: { top: 70, bottom: 70, left: 70, right: 70 },
|
||||
maxZoom: 14,
|
||||
speed: 10
|
||||
})
|
||||
})
|
||||
}
|
||||
mapIsLoaded.value = true
|
||||
}
|
||||
if (zoom && zoom.length) {
|
||||
paramsViewer = {
|
||||
map: {
|
||||
...paramsViewer.map,
|
||||
zoom: parseFloat(zoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxZoom && maxZoom.length) {
|
||||
paramsViewer = {
|
||||
map: {
|
||||
...paramsViewer.map,
|
||||
maxZoom: parseInt(maxZoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tiles && tiles.length) {
|
||||
const style = tiles.includes('wxs.ign.fr') ? await getIgnTiles() : tiles
|
||||
paramsViewer = {
|
||||
map: {
|
||||
...paramsViewer.map,
|
||||
style
|
||||
}
|
||||
}
|
||||
}
|
||||
if (props.fetchOptions) {
|
||||
paramsViewer = {
|
||||
...paramsViewer,
|
||||
...props.fetchOptions
|
||||
}
|
||||
}
|
||||
const reportLink = document.createElement('div')
|
||||
reportLink.className = 'gvs-group gvs-group-large gvs-group-btnpanel'
|
||||
viewer.value = new Viewer(
|
||||
'viewer', // Div ID
|
||||
`${import.meta.env.VITE_API_URL}/api/search`,
|
||||
{
|
||||
...paramsViewer,
|
||||
widgets: { customWidget: reportLink }
|
||||
}
|
||||
)
|
||||
if (viewer.value && viewer.value.addEventListener) {
|
||||
createViewerButton(reportLink)
|
||||
}
|
||||
mapIsLoaded.value = true
|
||||
}
|
||||
async function setupMap(tiles: string): Promise<void> {
|
||||
let paramsMap: MapInterface
|
||||
paramsMap = { minZoom: 7 }
|
||||
if (tiles && tiles.length) {
|
||||
const style = tiles.includes('wxs.ign.fr') ? await getIgnTiles() : tiles
|
||||
paramsMap = {
|
||||
...paramsMap,
|
||||
style
|
||||
}
|
||||
}
|
||||
const bbox = [props.bbox[0], props.bbox[1], props.bbox[2], props.bbox[3]]
|
||||
viewer.value = new StandaloneMap(
|
||||
'viewer', // Div ID
|
||||
`${import.meta.env.VITE_API_URL}/api/search`,
|
||||
{
|
||||
...paramsMap,
|
||||
bounds: bbox,
|
||||
zoom: 14
|
||||
}
|
||||
)
|
||||
viewer.value.addEventListener('ready', () => {
|
||||
viewer.value.setFilters({ user: props.userId }, true)
|
||||
viewer.value.fitBounds(bbox, {
|
||||
padding: { top: 70, bottom: 70, left: 70, right: 70 },
|
||||
maxZoom: 14,
|
||||
speed: 10
|
||||
})
|
||||
})
|
||||
mapIsLoaded.value = true
|
||||
}
|
||||
onMounted(async (): Promise<void> => {
|
||||
const tiles = import.meta.env.VITE_TILES
|
||||
try {
|
||||
if (props.geovisioViewer) return await setupViewerMap(tiles)
|
||||
return await setupMap(tiles)
|
||||
} catch (err) {
|
||||
mapIsLoaded.value = true
|
||||
console.log(err)
|
||||
}
|
||||
})
|
||||
onUnmounted(() => {
|
||||
onUnmounted((): void => {
|
||||
if (viewer.value && props.geovisioViewer) viewer.value.destroy()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
"pages": {
|
||||
"home": {
|
||||
"report_mail": "?subject=⚠️ Report on picture {picId}&body=HEllo, %0D%0A%0D%0A Problem on image (keep type of problem reported) : %0D%0A%0D%0A %0D%0A%0D%0A inappropriate content / lack of blurring on an element to be anonymized or blurred for security reasons / overblurring (too much blurring) %0D%0A%0D%0A Link to affected photo : {link} %0D%0A%0D%0A Details of affected elements (especially for blurring problems - what should be blurred or unblurred?) :",
|
||||
"report_button_text": "Report this picture"
|
||||
"report_button_text": "Report this picture",
|
||||
"sequence_title": "See the séquence"
|
||||
},
|
||||
"settings": {
|
||||
"title": "My tokens",
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
"pages": {
|
||||
"home": {
|
||||
"report_mail": "?subject=⚠️ Signalement sur l`image {picId}&body=Bonjour, %0D%0A%0D%0A Problème sur l`image (garder le type de problème signalé) : %0D%0A%0D%0A contenu inapproprié / absence de floutage sur un élément à anonymiser ou flouter pour des raisons de sécurité /surfloutage (floutage en trop) %0D%0A%0D%0A Lien vers la photo concernée : {link} %0D%0A%0D%0A Précision sur les éléments concernés (en particulier pour les problèmes de floutage - que faut-il flouter ou déflouter?) :",
|
||||
"report_button_text": "Signaler la photo"
|
||||
"report_button_text": "Signaler la photo",
|
||||
"sequence_title": "Voir la séquence"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Mes Tokens",
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
"pages": {
|
||||
"home": {
|
||||
"report_mail": "?subject=⚠️ Report on picture {picId}&body=Hello, %0D%0A%0D%0A Problem on image (keep type of problem reported) : %0D%0A%0D%0A %0D%0A%0D%0A inappropriate content / lack of blurring on an element to be anonymized or blurred for security reasons / overblurring (too much blurring) %0D%0A%0D%0A Link to affected photo : {link} %0D%0A%0D%0A Details of affected elements (especially for blurring problems - what should be blurred or unblurred?) :",
|
||||
"report_button_text": "Fénykép jelentése"
|
||||
"report_button_text": "Fénykép jelentése",
|
||||
"sequence_title": "lásd a sorrendet"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Saját tokenek",
|
||||
|
||||
@@ -3,7 +3,8 @@ import { defineStore } from 'pinia'
|
||||
export const useSequenceStore = defineStore('sequence', {
|
||||
state: () => ({
|
||||
toastText: <string>'',
|
||||
toastLook: <string>''
|
||||
toastLook: <string>'',
|
||||
picId: <string>''
|
||||
}),
|
||||
actions: {
|
||||
addToastText(text: string, look: string): void {
|
||||
@@ -12,6 +13,9 @@ export const useSequenceStore = defineStore('sequence', {
|
||||
setTimeout(() => {
|
||||
this.toastText = ''
|
||||
}, 3000)
|
||||
},
|
||||
addSequence(id: string): void {
|
||||
this.picId = id
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -7,7 +7,7 @@ async function getIgnTiles(): Promise<object> {
|
||||
data.sources.plan_ign.scheme = 'xyz'
|
||||
data.sources.plan_ign.attribution = 'Données cartographiques : © IGN'
|
||||
const objIndex = data.layers.findIndex(
|
||||
(el: any) => el.id === 'toponyme - parcellaire - adresse'
|
||||
(el: { id: string }) => el.id === 'toponyme - parcellaire - adresse'
|
||||
)
|
||||
data.layers[objIndex].layout = {
|
||||
...data.layers[objIndex].layout,
|
||||
|
||||
@@ -245,7 +245,7 @@ let isLoading = ref<boolean>(false)
|
||||
const collapseMenu = ref<HTMLDivElement>()
|
||||
const deleteAll = ref<HTMLDivElement>()
|
||||
const menuHeight = ref<string>()
|
||||
const viewerRef = ref()
|
||||
const viewerRef = ref<InstanceType<typeof Viewer>>()
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
@@ -266,37 +266,54 @@ onMounted(async () => {
|
||||
)
|
||||
pictures.value = collectionItems
|
||||
setHeightValue()
|
||||
if (itemSelected.value.length || !collectionItemsReady[0]) return
|
||||
if (
|
||||
itemSelected.value.length ||
|
||||
!getCurrentPicId(collectionItemsReady[0].id)
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (!viewerRef.value) return
|
||||
viewerRef.value.viewer._api.onceReady().then(() => {
|
||||
if (!viewerRef.value) return
|
||||
viewerRef.value.viewer.goToPicture(
|
||||
collectionItemsReady[0].id,
|
||||
getCurrentPicId(collectionItemsReady[0].id),
|
||||
sequence.value?.id
|
||||
)
|
||||
})
|
||||
itemSelected.value = collectionItemsReady[0].id
|
||||
scrollIntoSelected(collectionItemsReady[0].id, pictures.value)
|
||||
itemSelected.value = getCurrentPicId(collectionItemsReady[0].id)
|
||||
if (!pictureExistInList(getCurrentPicId(collectionItemsReady[0].id))) {
|
||||
await goToTheGoodPage(getCurrentPicId(collectionItemsReady[0].id))
|
||||
}
|
||||
scrollIntoSelected(
|
||||
itemSelected.value,
|
||||
pictures.value.map((e) => e.id)
|
||||
)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
})
|
||||
|
||||
watchEffect(async () => {
|
||||
if (!viewerExist(viewerRef)) return
|
||||
if (!viewerRef || !viewerRef.value || !viewerRef.value.viewer) return
|
||||
viewerRef.value.viewer.addEventListener(
|
||||
'picture-loaded',
|
||||
async (e: { detail: { picId: string } }): Promise<void> => {
|
||||
if (itemSelected.value === e.detail.picId) return
|
||||
if (!pictureExistInList(e.detail.picId)) {
|
||||
await goToTheGoodPage(e.detail.picId)
|
||||
if (!pictureExistInList(getCurrentPicId(e.detail.picId))) {
|
||||
await goToTheGoodPage(getCurrentPicId(e.detail.picId))
|
||||
}
|
||||
itemSelected.value = e.detail.picId
|
||||
scrollIntoSelected(e.detail.picId, pictures.value)
|
||||
itemSelected.value = getCurrentPicId(e.detail.picId)
|
||||
scrollIntoSelected(
|
||||
getCurrentPicId(e.detail.picId),
|
||||
pictures.value.map((e) => e.id)
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
function viewerExist(viewerRef: any): boolean {
|
||||
return !!(viewerRef && viewerRef.value && viewerRef.value.viewer)
|
||||
function getCurrentPicId(id: string): string {
|
||||
const parseParams = new URLSearchParams(window.location.search)
|
||||
const pict = parseParams.get('currentPic')
|
||||
return pict && pict.length ? pict : id
|
||||
}
|
||||
|
||||
const isSequenceOwner = computed((): boolean => {
|
||||
@@ -421,7 +438,7 @@ async function patchCollection(): Promise<void> {
|
||||
const { data } = await fetchCollectionItems(route.params.id, '?limit=100')
|
||||
pictures.value = data.features
|
||||
}
|
||||
viewerRef.value.viewer.reloadVectorTiles()
|
||||
if (viewerRef.value) viewerRef.value.viewer.reloadVectorTiles()
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
@@ -435,7 +452,10 @@ async function goToNextPage(value: string): Promise<void> {
|
||||
selfLink.value = data.links.filter((el) => el.rel === 'self')
|
||||
paginationLinks.value = formatPaginationItems(data.links)
|
||||
pictures.value = data.features
|
||||
scrollIntoSelected(pictures.value[0].id, pictures.value)
|
||||
scrollIntoSelected(
|
||||
pictures.value[0].id,
|
||||
pictures.value.map((e) => e.id)
|
||||
)
|
||||
picturesToDelete.value = []
|
||||
isLoading.value = false
|
||||
setHeightValue()
|
||||
@@ -484,16 +504,26 @@ function selectPhotoToDeleteOrPatch(
|
||||
async function selectImageAndMove(
|
||||
item: ResponseUserPhotoInterface
|
||||
): Promise<void> {
|
||||
const parseParams = new URLSearchParams(window.location.search)
|
||||
const pict = parseParams.get('currentPic')
|
||||
if (pict && pict.length) {
|
||||
await router.push({ name: 'sequence', params: { id: route.params.id } })
|
||||
}
|
||||
selectPhotoToDeleteOrPatch(item)
|
||||
if (
|
||||
picturesToDelete.value.length < 2 &&
|
||||
item.properties['geovisio:status'] === 'ready'
|
||||
) {
|
||||
const viewerMap = await viewerRef.value.viewer
|
||||
viewerMap.goToPicture(item.id, sequence.value?.id)
|
||||
if (viewerRef.value) {
|
||||
const viewerMap = await viewerRef.value.viewer
|
||||
viewerMap.goToPicture(item.id, sequence.value?.id)
|
||||
}
|
||||
itemSelected.value = item.id
|
||||
await goToTheGoodPage(item.id)
|
||||
scrollIntoSelected(item.id, pictures.value)
|
||||
scrollIntoSelected(
|
||||
item.id,
|
||||
pictures.value.map((e) => e.id)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,9 +583,14 @@ async function patchOrDeleteCollectionItems(
|
||||
const { data } = await fetchCollectionItems(route.params.id, '?limit=100')
|
||||
pictures.value = data.features
|
||||
isLoading.value = false
|
||||
viewerRef.value.viewer.reloadVectorTiles()
|
||||
viewerRef.value.viewer.goToPicture(pictures.value[0].id, route.params.id)
|
||||
scrollIntoSelected(picturesToDelete.value[0], pictures.value)
|
||||
if (viewerRef.value) {
|
||||
viewerRef.value.viewer.reloadVectorTiles()
|
||||
viewerRef.value.viewer.goToPicture(pictures.value[0].id, route.params.id)
|
||||
}
|
||||
scrollIntoSelected(
|
||||
picturesToDelete.value[0],
|
||||
pictures.value.map((e) => e.id)
|
||||
)
|
||||
picturesToDelete.value = []
|
||||
sequenceStore.addToastText(t('general.success_text'), 'success')
|
||||
} catch (e) {
|
||||
|
||||
@@ -72,10 +72,7 @@
|
||||
<li
|
||||
v-if="userSequences.length"
|
||||
v-for="item in userSequences"
|
||||
:class="[
|
||||
'sequence-item',
|
||||
item.id === seqId ? 'button-item-hover' : ''
|
||||
]"
|
||||
class="sequence-item"
|
||||
@mouseover="goToSequence(item)"
|
||||
>
|
||||
<router-link
|
||||
@@ -233,9 +230,9 @@ let mapWidth = ref<number>(window.innerWidth / 3)
|
||||
let listWidth = ref<number>(window.innerWidth / 1.5)
|
||||
const windowWidth = ref<number>(window.innerWidth)
|
||||
const windowHeight = ref<number>(window.innerHeight - 80)
|
||||
const viewerRef = ref<any>(null)
|
||||
const headerList = ref<any>(null)
|
||||
const list = ref<any>(null)
|
||||
const viewerRef = ref<InstanceType<typeof Viewer>>()
|
||||
const headerList = ref<HTMLDivElement | null>(null)
|
||||
const list = ref<HTMLDListElement | null>(null)
|
||||
const listPos = ref<PositionInterface | null>(null)
|
||||
const headerLisPos = ref<PositionInterface | null>(null)
|
||||
|
||||
@@ -252,7 +249,7 @@ async function patchCollection(sequence: SequenceLinkInterface): Promise<void> {
|
||||
else visible = 'true'
|
||||
await patchACollection(sequence.id, visible)
|
||||
await fetchAndFormatSequence()
|
||||
viewerRef.value.viewer.reloadVectorTiles()
|
||||
if (viewerRef.value) viewerRef.value.viewer.reloadVectorTiles()
|
||||
isLoading.value = false
|
||||
}
|
||||
async function deleteCollection(
|
||||
@@ -262,7 +259,7 @@ async function deleteCollection(
|
||||
if (confirm(t('pages.sequence.confirm_sequence_dialog'))) {
|
||||
await deleteACollection(sequence.id)
|
||||
await fetchAndFormatSequence()
|
||||
viewerRef.value.viewer.reloadVectorTiles()
|
||||
if (viewerRef.value) viewerRef.value.viewer.reloadVectorTiles()
|
||||
}
|
||||
isLoading.value = false
|
||||
}
|
||||
@@ -313,15 +310,21 @@ function bboxIsInsideOther(mainBbox: number[], bboxInside: number[]): boolean {
|
||||
)
|
||||
}
|
||||
function goToSequence(sequence: SequenceLinkInterface): void {
|
||||
seqId.value = sequence.id
|
||||
viewerRef.value.viewer.select(seqId.value)
|
||||
if (!viewerRef.value) return
|
||||
const currentBbox = [
|
||||
viewerRef.value.viewer._map.getBounds()._ne.lng,
|
||||
viewerRef.value.viewer._map.getBounds()._ne.lat,
|
||||
viewerRef.value.viewer._map.getBounds()._sw.lng,
|
||||
viewerRef.value.viewer._map.getBounds()._sw.lat
|
||||
]
|
||||
if (bboxIsInsideOther(currentBbox, sequence.extent.spatial.bbox[0])) return
|
||||
if (
|
||||
seqId.value === sequence.id &&
|
||||
bboxIsInsideOther(currentBbox, sequence.extent.spatial.bbox[0])
|
||||
) {
|
||||
return
|
||||
}
|
||||
seqId.value = sequence.id
|
||||
viewerRef.value.viewer.select(seqId.value)
|
||||
viewerRef.value.viewer._map.flyTo({
|
||||
center: [
|
||||
sequence.extent.spatial.bbox[0][0],
|
||||
@@ -386,9 +389,13 @@ watchEffect(() => {
|
||||
viewerRef.value.viewer.addEventListener(
|
||||
'hover',
|
||||
(e: { detail: { seqId: string } }) => {
|
||||
if (seqId.value === e.detail.seqId) return
|
||||
seqId.value = e.detail.seqId
|
||||
scrollIntoSelected(e.detail.seqId, userSequences.value)
|
||||
viewerRef.value.viewer.select(e.detail.seqId)
|
||||
scrollIntoSelected(
|
||||
e.detail.seqId,
|
||||
userSequences.value.map((e) => e.id)
|
||||
)
|
||||
if (viewerRef.value) viewerRef.value.viewer.select(e.detail.seqId)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -454,6 +461,16 @@ watchEffect(() => {
|
||||
&:nth-child(2n) {
|
||||
background-color: var(--white);
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--blue);
|
||||
color: var(--white);
|
||||
.button-item {
|
||||
& > *,
|
||||
& > :nth-child(2) {
|
||||
color: var(--white);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.wrapper-button {
|
||||
position: absolute;
|
||||
@@ -468,18 +485,6 @@ watchEffect(() => {
|
||||
margin-bottom: toRem(1);
|
||||
}
|
||||
}
|
||||
.button-item-hover {
|
||||
background-color: var(--blue);
|
||||
&:nth-child(2n) {
|
||||
background-color: var(--blue);
|
||||
}
|
||||
.button-item {
|
||||
& > *,
|
||||
& > :nth-child(2) {
|
||||
color: var(--white);
|
||||
}
|
||||
}
|
||||
}
|
||||
.item-head-fixed {
|
||||
position: fixed;
|
||||
top: toRem(8);
|
||||
|
||||
@@ -229,7 +229,7 @@ async function uploadPicture(): Promise<void> {
|
||||
body.append('picture', el)
|
||||
try {
|
||||
const pictureUploaded = await createAPictureToASequence(data.id, body)
|
||||
const pictures = { ...pictureUploaded.data, name: el.name }
|
||||
const pictures = { ...pictureUploaded, name: el.name }
|
||||
picturesUploadingSize.value = picturesUploadingSize.value + el.size
|
||||
uploadedSequence.value.pictures = [
|
||||
...uploadedSequence.value.pictures,
|
||||
|
||||
@@ -7,9 +7,8 @@ function imageStatus(imageStatus: string, sequenceStatus: string): string {
|
||||
if (sequenceStatus === 'hidden') return sequenceStatus
|
||||
return imageStatus
|
||||
}
|
||||
//TODO REMOVE ANY
|
||||
function scrollIntoSelected(id: string, userPhotos: any): void {
|
||||
const itemPosition = userPhotos.map((el: any) => el.id).indexOf(id)
|
||||
function scrollIntoSelected(id: string, userPhotos: string[]): void {
|
||||
const itemPosition = userPhotos.map((el: string) => el).indexOf(id)
|
||||
const elementTarget = document.querySelector(`#el-list${itemPosition}`)
|
||||
if (elementTarget) elementTarget.scrollIntoView({ behavior: 'smooth' })
|
||||
}
|
||||
|
||||
@@ -19,12 +19,32 @@ interface SequenceCreatedInterface {
|
||||
}
|
||||
}
|
||||
|
||||
interface PictureCreatedInterface {
|
||||
data: {
|
||||
assets: object
|
||||
bbox: number[]
|
||||
collection: string
|
||||
geometry: object
|
||||
id: string
|
||||
links: object[]
|
||||
properties: object
|
||||
providers: object[]
|
||||
stac_extensions: string[]
|
||||
stac_version: string
|
||||
type: string
|
||||
}
|
||||
}
|
||||
|
||||
function createASequence(title: string): Promise<SequenceCreatedInterface> {
|
||||
return axios.post('api/collections', { title: title })
|
||||
}
|
||||
|
||||
async function createAPictureToASequence(id: string, body: any): Promise<any> {
|
||||
return await axios.post(`api/collections/${id}/items`, body)
|
||||
async function createAPictureToASequence(
|
||||
id: string,
|
||||
body: FormData
|
||||
): Promise<PictureCreatedInterface> {
|
||||
const { data } = await axios.post(`api/collections/${id}/items`, body)
|
||||
return data
|
||||
}
|
||||
|
||||
export { createASequence, createAPictureToASequence }
|
||||
|
||||
Reference in New Issue
Block a user