diff --git a/package.json b/package.json
index 22a56b0..2127be3 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,7 @@
"axios": "^1.2.3",
"bootstrap": "^5.2.3",
"bootstrap-icons": "^1.10.3",
- "geovisio": "2.5.0",
+ "geovisio": "2.5.1",
"moment": "^2.29.4",
"pako": "^2.1.0",
"pinia": "^2.1.4",
diff --git a/src/App.vue b/src/App.vue
index 898c338..3d3c881 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -3,11 +3,9 @@ import { ref, computed } from 'vue'
import Header from '@/components/Header.vue'
import Footer from '@/components/Footer.vue'
import { RouterView } from 'vue-router'
-import { useI18n } from 'vue-i18n'
import { hasASessionCookieDecoded } from '@/utils/auth'
import authConfig from './composables/auth'
const { authConf } = authConfig()
-const { t } = useI18n()
let focusMap = ref('focus-map')
diff --git a/src/assets/components/index.scss b/src/assets/components/index.scss
new file mode 100644
index 0000000..fd8793f
--- /dev/null
+++ b/src/assets/components/index.scss
@@ -0,0 +1,14 @@
+@mixin switch-button-view() {
+ position: fixed;
+ right: 0;
+ top: toRem(22);
+ z-index: 3;
+ height: toRem(5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-top-left-radius: toRem(0.5);
+ border-bottom-left-radius: toRem(0.5);
+ background-color: var(--white);
+ border: toRem(0.1) solid var(--grey-pale);
+}
\ No newline at end of file
diff --git a/src/assets/font-size.scss b/src/assets/font-size.scss
index f8ca0f7..f826f34 100644
--- a/src/assets/font-size.scss
+++ b/src/assets/font-size.scss
@@ -28,7 +28,7 @@
}
@if $size == h4 {
font-weight: normal;
- font-size: toRem(1.6);
+ font-size: toRem(1.8);
}
@if $size == xxl-regular {
font-size: toRem(3.2);
diff --git a/src/assets/images/car.svg b/src/assets/images/car.svg
new file mode 100644
index 0000000..6066a20
--- /dev/null
+++ b/src/assets/images/car.svg
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/images/cursor.svg b/src/assets/images/cursor.svg
new file mode 100644
index 0000000..012e293
--- /dev/null
+++ b/src/assets/images/cursor.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/images/icon/cursor-arrow.svg b/src/assets/images/icon/cursor-arrow.svg
new file mode 100644
index 0000000..0c0814f
--- /dev/null
+++ b/src/assets/images/icon/cursor-arrow.svg
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/images/road.svg b/src/assets/images/road.svg
new file mode 100644
index 0000000..8e3b3b9
--- /dev/null
+++ b/src/assets/images/road.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/assets/main.scss b/src/assets/main.scss
index 96b931a..ddd4c80 100644
--- a/src/assets/main.scss
+++ b/src/assets/main.scss
@@ -34,10 +34,11 @@ h5 {
--grey-pale: #cfd2cf;
--grey-semi-dark: #808080;
--grey-dark: #3e3e3e;
- --blue: #2954e9;
--blue-dark: #0a1f69;
- --blue-semi: #d7dffc;
+ --blue: #2954e9;
+ --blue-semi-pale: #f2f5ff;
--blue-pale: #f2f5ff;
+ --blue-very-pale: #f9faff;
--blue-geovisio: #34495e;
--beige: #f5f3ec;
--yellow: #fec868;
diff --git a/src/components/Button.vue b/src/components/Button.vue
index e0e60bf..0e21637 100644
--- a/src/components/Button.vue
+++ b/src/components/Button.vue
@@ -82,6 +82,7 @@ defineProps({
.button--blue {
color: var(--white);
background-color: var(--blue);
+ height: toRem(4);
&.disabled {
opacity: 0.6;
color: var(--white);
@@ -140,6 +141,7 @@ defineProps({
.no-text-white .icon {
color: var(--white);
margin-right: 0;
+ font-size: toRem(1.4);
}
.no-text-blue-dark .icon {
color: var(--blue-dark);
diff --git a/src/components/EditText.vue b/src/components/EditText.vue
index c867dc3..8295fd8 100644
--- a/src/components/EditText.vue
+++ b/src/components/EditText.vue
@@ -36,7 +36,7 @@
{{ text }}
(() => props.isLoading && !props.isLoaded)
align-items: center;
}
.edit-mode {
- background-color: var(--blue-pale);
+ background-color: var(--blue-very-pale);
padding: toRem(1);
border-radius: toRem(0.4);
+ width: 100%;
}
.wrapper-edit {
display: flex;
@@ -121,7 +122,7 @@ const isDisabled = computed(() => props.isLoading && !props.isLoaded)
width: 100%;
}
.edit-button {
- background-color: var(--grey);
+ background-color: var(--blue);
border-radius: 50%;
height: toRem(2.5);
width: toRem(2.5);
@@ -150,7 +151,7 @@ const isDisabled = computed(() => props.isLoading && !props.isLoaded)
height: toRem(2);
width: toRem(2);
top: toRem(-1);
- right: toRem(-1);
+ left: toRem(-1);
background-color: var(--blue-dark);
color: var(--white);
border-radius: 50%;
diff --git a/src/components/InformationCard.vue b/src/components/InformationCard.vue
index de48332..676450b 100644
--- a/src/components/InformationCard.vue
+++ b/src/components/InformationCard.vue
@@ -10,9 +10,7 @@
alt=""
class="icon-block-img"
/>
-
- {{ title }}
-
+
@@ -23,7 +21,6 @@
@@ -36,11 +33,11 @@ h3 {
.information-block {
position: relative;
border-left: toRem(1.4) solid var(--blue);
- padding: toRem(2) toRem(2) toRem(1.5);
+ padding: toRem(1.8) toRem(1.8) toRem(1.3);
background-color: var(--white);
border-radius: toRem(1.5);
display: flex;
- align-items: flex-end;
+ align-items: center;
justify-content: space-between;
flex-wrap: wrap;
}
@@ -61,10 +58,6 @@ h3 {
margin-right: toRem(0.5);
height: toRem(2.2);
}
-.subtitle {
- @include text(h2);
- color: var(--blue-dark);
-}
.information-text {
margin-top: toRem(1);
@include text(m-r-regular);
diff --git a/src/components/Input.vue b/src/components/Input.vue
index ebb7afc..0fc8f61 100644
--- a/src/components/Input.vue
+++ b/src/components/Input.vue
@@ -3,16 +3,21 @@
:value="text"
:required="true"
:placeholder="placeholder"
- class="input"
- type="text"
+ :type="type"
+ :min="min"
+ :max="max"
@input="emitValue"
+ class="input"
/>
@@ -54,6 +59,8 @@ function updateValue(value: boolean): void {
align-items: center;
height: toRem(2);
width: toRem(2);
+ background-color: var(--white);
+ border-radius: toRem(0.5);
}
.input {
-webkit-appearance: none;
@@ -68,7 +75,7 @@ function updateValue(value: boolean): void {
.icon {
font-size: toRem(2);
position: absolute;
- color: var(--grey-semi-dark);
+ color: var(--blue);
}
.wrapper-checkbox {
display: flex;
@@ -77,5 +84,14 @@ function updateValue(value: boolean): void {
.label {
cursor: pointer;
margin-left: toRem(0.5);
+ @include text(s-r-regular);
+}
+.checked {
+ .input-checkbox {
+ background-color: var(--blue);
+ }
+ .icon {
+ color: var(--white);
+ }
}
diff --git a/src/components/InputRadio.vue b/src/components/InputRadio.vue
new file mode 100644
index 0000000..4c1ed74
--- /dev/null
+++ b/src/components/InputRadio.vue
@@ -0,0 +1,36 @@
+
+
+
+ {{
+ label
+ }}
+
+
+
+
+
+
diff --git a/src/components/InputSwitch.vue b/src/components/InputSwitch.vue
new file mode 100644
index 0000000..940b7de
--- /dev/null
+++ b/src/components/InputSwitch.vue
@@ -0,0 +1,76 @@
+
+
+
+
+ {{ $t('pages.sequence.sort_panel_settings_order_increase') }}
+
+
+
+ {{ $t('pages.sequence.sort_panel_settings_order_decrease') }}
+
+
+
+
+
+
+
+
diff --git a/src/components/Link.vue b/src/components/Link.vue
index 9777c57..e797959 100644
--- a/src/components/Link.vue
+++ b/src/components/Link.vue
@@ -124,6 +124,17 @@ function triggerButton() {
margin-right: toRem(0.5);
}
}
+.link--grey-dark {
+ color: var(--grey-dark);
+ text-decoration: underline;
+ font-weight: inherit;
+ font-size: toRem(1.4);
+ .icon {
+ color: var(--grey-dark);
+ font-size: toRem(1.4);
+ margin-right: toRem(0.5);
+ }
+}
.link--blue-dark {
color: var(--blue-dark);
.icon {
@@ -169,7 +180,7 @@ function triggerButton() {
}
}
.button--blue-bleu {
- background-color: var(--blue-semi);
+ background-color: var(--blue-semi-pale);
color: var(--blue);
}
.disabled {
diff --git a/src/components/TabPanel.vue b/src/components/TabPanel.vue
new file mode 100644
index 0000000..7aa30fd
--- /dev/null
+++ b/src/components/TabPanel.vue
@@ -0,0 +1,49 @@
+
+
+
+ {{ $t('pages.sequence.button_panel_photos') }}
+
+
+ {{ $t('pages.sequence.button_panel_orientation') }}
+
+
+ {{ $t('pages.sequence.button_panel_sort') }}
+
+
+
+
+
+
+
diff --git a/src/components/Toast.vue b/src/components/Toast.vue
index df8b99a..738c061 100644
--- a/src/components/Toast.vue
+++ b/src/components/Toast.vue
@@ -39,6 +39,7 @@ defineProps({
min-width: toRem(10);
padding-right: toRem(1);
padding-left: toRem(1);
+ z-index: 1;
}
.button-close {
position: absolute;
diff --git a/src/components/Viewer.vue b/src/components/Viewer.vue
index a85a60e..b49ca34 100644
--- a/src/components/Viewer.vue
+++ b/src/components/Viewer.vue
@@ -1,5 +1,5 @@
-
+
+
+
diff --git a/src/components/sequence/PanelPhotosManagement.vue b/src/components/sequence/PanelPhotosManagement.vue
new file mode 100644
index 0000000..d3ee1af
--- /dev/null
+++ b/src/components/sequence/PanelPhotosManagement.vue
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+ -
+ {{
+ $t('pages.sequence.picture_selected', picturesToDelete.length)
+ }}
+
+
+
+
+
+
+ {{ $t('pages.sequence.no_image') }}
+
+
+
+
+
diff --git a/src/components/sequence/PanelSortManagement.vue b/src/components/sequence/PanelSortManagement.vue
new file mode 100644
index 0000000..b622eb5
--- /dev/null
+++ b/src/components/sequence/PanelSortManagement.vue
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
diff --git a/src/components/sequence/WidgetOrientation.vue b/src/components/sequence/WidgetOrientation.vue
new file mode 100644
index 0000000..f39dd15
--- /dev/null
+++ b/src/components/sequence/WidgetOrientation.vue
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
diff --git a/src/locales/en.json b/src/locales/en.json
index 5454d94..a054d34 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -56,8 +56,25 @@
"delete_sequence_tooltip": "Permanently delete this sequence",
"hide_photo_tooltip": "Hide selected pictures",
"delete_photo_tooltip": "Permanently delete selected pictures",
- "confirm_pictures_dialog": "⚠️ Selected photos will be permanently deleted",
- "confirm_sequence_dialog": "⚠️ This sequence will be permanently deleted",
+ "conf_pic_msg": "⚠️ Selected photos will be permanently deleted",
+ "conf_sequence_msg": "⚠️ This sequence will be permanently deleted",
+ "button_panel_photos": "Manage pictures",
+ "button_panel_orientation": "Set orientation",
+ "button_panel_sort": "Sort sequence",
+ "orientation_panel_title": "Adjusting the orientation of all photos in the sequence",
+ "orientation_panel_tooltip": "Drag the blue box in the desired direction\"",
+ "orientation_input_label": "or change the angle here",
+ "orientation_input_placeholder": "Value between -180 and 180",
+ "orientation_input_error_value": "Value must be between -180 and 180",
+ "orientation_panel_button": "Validate position",
+ "sort_panel_title": "Sequence sort setting",
+ "sort_panel_settings": "Sort sequence by:",
+ "sort_panel_settings_order": "Order :",
+ "sort_panel_settings_order_increase": "Ascending",
+ "sort_panel_settings_order_decrease": "Decreasing",
+ "sort_panel_check_gps": "GPS Date",
+ "sort_panel_check_file": "File date",
+ "sort_panel_check_name": "File name",
"created": "Uploaded :",
"taken": "Shot on :",
"duration": "Duration :",
diff --git a/src/locales/fr.json b/src/locales/fr.json
index bb0becc..717ebff 100644
--- a/src/locales/fr.json
+++ b/src/locales/fr.json
@@ -1,7 +1,6 @@
{
"general": {
- "title": "DESC Panoramax {instanceName}: photo-cartographier les territoires",
- "description": "DESC L'instance Panoramax {instanceName} permet la publication de photo de terrain pour cartographier le territoire. Panoramax favorise la réutilisation des photos pour de nombreux cas d'usages.",
+ "title": "Instance Panoramax",
"meta": {
"title": "Instance Panoramax",
"description": "Panoramax, l’alternative libre pour photo-cartographier les territoires"
@@ -57,8 +56,27 @@
"delete_sequence_tooltip": "Supprime définitivement la séquence",
"hide_photo_tooltip": "Masque les photos sur la carte",
"delete_photo_tooltip": "Supprime définitivement les photos",
- "confirm_pictures_dialog": "⚠️ Les photos sélectionnées vont être définitivement supprimées",
- "confirm_sequence_dialog": "⚠️ La séquence va être définitivement supprimée",
+ "conf_pic_msg": "⚠️ Les photos sélectionnées vont être définitivement supprimées",
+ "conf_sequence_msg": "⚠️ La séquence va être définitivement supprimée",
+ "button_panel_photos": "Gérer les photos",
+ "button_panel_orientation": "Régler l'orientation",
+ "button_panel_sort": "Trier la séquence",
+ "orientation_panel_title": "Définir l'orientation de la caméra sur le véhicule",
+ "orientation_panel_tooltip": "Faites glisser la zone bleu dans la direction souhaitée",
+ "orientation_input_label": "ou modifiez l'angle ici",
+ "orientation_input_placeholder": "Valeur entre -180 et 180",
+ "orientation_input_error_value": "La valeur doit être entre -180 et 180",
+ "orientation_panel_button": "Valider la position",
+ "orientation_updated": "L'orientation a bien été modifiée",
+ "sort_updated": "La séquence a bien triée",
+ "sort_panel_title": "Réglage du tri de la séquence",
+ "sort_panel_settings": "Trier la séquence par :",
+ "sort_panel_settings_order": "Ordre :",
+ "sort_panel_settings_order_increase": "Croissant",
+ "sort_panel_settings_order_decrease": "Décroissant",
+ "sort_panel_check_gps": "Date du GPS",
+ "sort_panel_check_file": "Date de la caméra",
+ "sort_panel_check_name": "Nom du fichier",
"created": "Versement :",
"taken": "Prise de vue :",
"duration": "Durée :",
diff --git a/src/locales/hu.json b/src/locales/hu.json
index 4e2f679..3dafb95 100644
--- a/src/locales/hu.json
+++ b/src/locales/hu.json
@@ -56,8 +56,25 @@
"delete_sequence_tooltip": "A sorozat végleges törlése",
"hide_photo_tooltip": "A kiválasztott fényképek elrejtése",
"delete_photo_tooltip": "A kiválasztottt fényképek végleges törlése",
- "confirm_pictures_dialog": "⚠️ A kiválasztott fényképek véglegesen elvesznek",
- "confirm_sequence_dialog": "⚠️ A kiválasztott sorozat véglegesen elvész",
+ "conf_pic_msg": "⚠️ A kiválasztott fényképek véglegesen elvesznek",
+ "conf_sequence_msg": "⚠️ A kiválasztott sorozat véglegesen elvész",
+ "button_panel_photos": "Fényképek kezelése",
+ "button_panel_orientation": "Tájolás beállítása",
+ "button_panel_sort": "Rendezési sorrend",
+ "orientation_panel_title": "Az összes kép tájolásának beállítása a sorozatban",
+ "orientation_panel_tooltip": "Húzza a kék dobozt a kívánt irányba",
+ "orientation_input_label": "vagy módosítsa a szöget itt",
+ "orientation_input_placeholder": "-180 és 180 közötti érték",
+ "orientation_input_error_value": "Az értéknek -180 és 180 között kell lennie",
+ "orientation_panel_button": "Pozíció ellenőrzése",
+ "sort_panel_title": "Szekvenciás rendezés beállítása",
+ "sort_panel_settings": "Sorrend rendezése:",
+ "sort_panel_settings_order": "Rendelés :",
+ "sort_panel_settings_order_increase": "Növekvő",
+ "sort_panel_settings_order_decrease": "Csökkenő",
+ "sort_panel_check_gps": "GPS dátum",
+ "sort_panel_check_file": "Fájl dátuma",
+ "sort_panel_check_name": "Fájlnév",
"created": "Feltöltés ideje:",
"taken": "Elkészítés ideje:",
"duration": "Hossz:",
diff --git a/src/tests/unit/components/InformationCard.spec.js b/src/tests/unit/components/InformationCard.spec.js
index 2a83bec..0ebffa6 100644
--- a/src/tests/unit/components/InformationCard.spec.js
+++ b/src/tests/unit/components/InformationCard.spec.js
@@ -11,7 +11,6 @@ describe('Template', () => {
}
})
expect(wrapper.vm.text).toBe(null)
- expect(wrapper.vm.title).toBe(null)
expect(wrapper.vm.look).toBe('')
})
test('should have all the props filled', () => {
@@ -21,11 +20,9 @@ describe('Template', () => {
},
props: {
text: 'my text',
- title: 'my title',
look: 'my-look'
}
})
- expect(wrapper.html()).contains('my title')
expect(wrapper.html()).contains('my text
')
expect(wrapper.html()).contains('class="information-block my-look"')
})
diff --git a/src/tests/unit/components/sequence/PanelOrientationManagement.spec.js b/src/tests/unit/components/sequence/PanelOrientationManagement.spec.js
new file mode 100644
index 0000000..684ca3d
--- /dev/null
+++ b/src/tests/unit/components/sequence/PanelOrientationManagement.spec.js
@@ -0,0 +1,74 @@
+import { it, describe, expect } from 'vitest'
+import { shallowMount } from '@vue/test-utils'
+import PanelOrientationManagement from '../../../../components/sequence/PanelOrientationManagement.vue'
+import i18n from '../../config'
+
+describe('Template', () => {
+ describe('Props', () => {
+ it('should have default props', () => {
+ const wrapper = shallowMount(PanelOrientationManagement, {
+ global: {
+ plugins: [i18n],
+ mocks: {
+ $t: (msg) => msg
+ }
+ }
+ })
+
+ expect(wrapper.vm.roadDegrees).toBe(0)
+ expect(wrapper.vm.seqBruteDeg).toBe(0)
+ })
+ describe('When the component have props filled', () => {
+ it('should render the component all the element', () => {
+ const wrapper = shallowMount(PanelOrientationManagement, {
+ global: {
+ plugins: [i18n],
+ mocks: {
+ $t: (msg) => msg
+ }
+ },
+ props: {
+ roadDegrees: 45,
+ seqBruteDeg: 22
+ }
+ })
+ expect(wrapper.html()).contains(
+ 'pages.sequence.orientation_panel_title'
+ )
+ expect(wrapper.html()).contains(
+ 'pages.sequence.orientation_input_label'
+ )
+ expect(wrapper.html()).contains(
+ 'pages.sequence.orientation_input_placeholder'
+ )
+ expect(wrapper.html()).contains(' {
+ it('should emit triggerAngle event', async () => {
+ const wrapper = shallowMount(PanelOrientationManagement, {
+ global: {
+ plugins: [i18n],
+ mocks: {
+ $t: (msg) => msg
+ }
+ },
+ props: {
+ roadDegrees: 45,
+ seqBruteDeg: 22
+ }
+ })
+ const valueToEmit = 22 - 45
+ await wrapper.vm.triggerAngle(valueToEmit)
+ expect(wrapper.emitted('triggerAngle')).toHaveLength(1)
+ expect(wrapper.emitted('triggerAngle')[0]).toEqual([valueToEmit])
+ })
+ })
+ })
+})
diff --git a/src/tests/unit/components/sequence/PanelPhotosManagement.spec.js b/src/tests/unit/components/sequence/PanelPhotosManagement.spec.js
new file mode 100644
index 0000000..54fb5e4
--- /dev/null
+++ b/src/tests/unit/components/sequence/PanelPhotosManagement.spec.js
@@ -0,0 +1,347 @@
+import { it, describe, expect } from 'vitest'
+import { shallowMount } from '@vue/test-utils'
+import PanelPhotosManagement from '../../../../components/sequence/PanelPhotosManagement.vue'
+import i18n from '../../config'
+import { createPinia } from 'pinia'
+const pinia = createPinia()
+
+describe('Template', () => {
+ describe('Props', () => {
+ it('should have default props', () => {
+ const wrapper = shallowMount(PanelPhotosManagement, {
+ global: {
+ plugins: [i18n, pinia],
+ mocks: {
+ $t: (msg) => msg
+ }
+ }
+ })
+
+ expect(wrapper.vm.isSequenceOwner).toBe(false)
+ expect(wrapper.vm.imagesSelectedHaveDifferentStatus).toBe(false)
+ expect(wrapper.vm.itemSelected).toBe('')
+ expect(wrapper.vm.menuHeight).toBe('0')
+ expect(wrapper.vm.fullImagesToDelete).toStrictEqual([])
+ expect(wrapper.vm.selfLink).toStrictEqual([])
+ expect(wrapper.vm.paginationLinks).toStrictEqual([])
+ expect(wrapper.vm.pictures).toStrictEqual([])
+ expect(wrapper.vm.picturesToDelete).toStrictEqual([])
+ expect(wrapper.vm.sequence).toStrictEqual({})
+ })
+ describe('When the component have props filled', () => {
+ it('should render the component with images selected', () => {
+ const pictures = [
+ {
+ assets: { thumb: { href: 'thumbHref' }, hd: { href: 'hdHref' } },
+ properties: { datetime: new Date(), 'geovisio:status': 'ready' },
+ id: 'pictureId',
+ bbox: [1, 2, 3, 4]
+ }
+ ]
+ const sequence = [
+ {
+ id: 'seqId',
+ title: 'title',
+ description: 'descr',
+ license: 'license',
+ created: new Date(),
+ taken: 'taken date',
+ location: 'location',
+ imageCount: 4,
+ duration: 'duration',
+ camera: 'camera',
+ cameraModel: 'camera model',
+ status: 'ready',
+ providers: [{ name: 'provider', roles: ['role1'] }],
+ extent: {
+ temporal: { interval: ['date'] },
+ spatial: { bbox: ['1', '2'] }
+ }
+ }
+ ]
+ const paginationLinks = [
+ {
+ href: 'href',
+ rel: 'rel',
+ title: 'title',
+ type: 'type'
+ }
+ ]
+ const selfLink = [
+ {
+ href: 'href',
+ rel: 'self',
+ title: 'title',
+ type: 'type'
+ }
+ ]
+ const fullImagesToDelete = [
+ {
+ assets: { thumb: { href: 'thumbHref' }, hd: { href: 'hdHref' } },
+ properties: { datetime: new Date(), 'geovisio:status': 'ready' },
+ id: 'pictureId',
+ bbox: [1, 2, 3, 4]
+ }
+ ]
+ const wrapper = shallowMount(PanelPhotosManagement, {
+ global: {
+ plugins: [i18n, pinia],
+ mocks: {
+ $t: (msg) => msg
+ }
+ },
+ props: {
+ isSequenceOwner: true,
+ imagesSelectedHaveDifferentStatus: true,
+ itemSelected: 'pictureId',
+ menuHeight: '10px',
+ pictures,
+ picturesToDelete: ['1', '2'],
+ sequence,
+ paginationLinks,
+ selfLink,
+ fullImagesToDelete
+ }
+ })
+ expect(wrapper.html()).contains(' {
+ const pictures = []
+ const sequence = [
+ {
+ id: 'seqId',
+ title: 'title',
+ description: 'descr',
+ license: 'license',
+ created: new Date(),
+ taken: 'taken date',
+ location: 'location',
+ imageCount: 4,
+ duration: 'duration',
+ camera: 'camera',
+ cameraModel: 'camera model',
+ status: 'ready',
+ providers: [{ name: 'provider', roles: ['role1'] }],
+ extent: {
+ temporal: { interval: ['date'] },
+ spatial: { bbox: ['1', '2'] }
+ }
+ }
+ ]
+ const paginationLinks = []
+ const selfLink = [
+ {
+ href: 'href',
+ rel: 'self',
+ title: 'title',
+ type: 'type'
+ }
+ ]
+ const fullImagesToDelete = []
+ const wrapper = shallowMount(PanelPhotosManagement, {
+ global: {
+ plugins: [i18n, pinia],
+ mocks: {
+ $t: (msg) => msg
+ }
+ },
+ props: {
+ isSequenceOwner: true,
+ imagesSelectedHaveDifferentStatus: false,
+ itemSelected: '',
+ menuHeight: '10px',
+ pictures,
+ picturesToDelete: [],
+ sequence,
+ paginationLinks,
+ selfLink,
+ fullImagesToDelete
+ }
+ })
+ expect(wrapper.html()).contains('class="no-photo"')
+ expect(wrapper.html()).contains('pages.sequence.no_image')
+ })
+ it('should render the component with all the images selected', () => {
+ const pictures = [
+ {
+ assets: { thumb: { href: 'thumbHref' }, hd: { href: 'hdHref' } },
+ properties: { datetime: new Date(), 'geovisio:status': 'ready' },
+ id: 'pictureId',
+ bbox: [1, 2, 3, 4]
+ }
+ ]
+ const sequence = [
+ {
+ id: 'seqId',
+ title: 'title',
+ description: 'descr',
+ license: 'license',
+ created: new Date(),
+ taken: 'taken date',
+ location: 'location',
+ imageCount: 4,
+ duration: 'duration',
+ camera: 'camera',
+ cameraModel: 'camera model',
+ status: 'ready',
+ providers: [{ name: 'provider', roles: ['role1'] }],
+ extent: {
+ temporal: { interval: ['date'] },
+ spatial: { bbox: ['1', '2'] }
+ }
+ }
+ ]
+ const wrapper = shallowMount(PanelPhotosManagement, {
+ global: {
+ plugins: [i18n, pinia],
+ mocks: {
+ $t: (msg) => msg
+ }
+ },
+ props: {
+ isSequenceOwner: true,
+ pictures,
+ picturesToDelete: [1],
+ sequence
+ }
+ })
+ expect(wrapper.html()).contains(
+ 'ischecked="true" isindeterminate="false"> {
+ const pictures = [
+ {
+ assets: { thumb: { href: 'thumbHref' }, hd: { href: 'hdHref' } },
+ properties: { datetime: new Date(), 'geovisio:status': 'hidden' },
+ id: 'pictureId',
+ bbox: [1, 2, 3, 4]
+ }
+ ]
+ const sequence = [
+ {
+ id: 'seqId',
+ title: 'title',
+ description: 'descr',
+ license: 'license',
+ created: new Date(),
+ taken: 'taken date',
+ location: 'location',
+ imageCount: 4,
+ duration: 'duration',
+ camera: 'camera',
+ cameraModel: 'camera model',
+ status: 'ready',
+ providers: [{ name: 'provider', roles: ['role1'] }],
+ extent: {
+ temporal: { interval: ['date'] },
+ spatial: { bbox: ['1', '2'] }
+ }
+ }
+ ]
+ const wrapper = shallowMount(PanelPhotosManagement, {
+ global: {
+ plugins: [i18n, pinia],
+ mocks: {
+ $t: (msg) => msg
+ }
+ },
+ props: {
+ isSequenceOwner: true,
+ pictures,
+ picturesToDelete: [],
+ sequence
+ }
+ })
+ expect(wrapper.html()).contains('status="hidden"> {
+ it('should emit triggerInputCheck event', async () => {
+ const wrapper = shallowMount(PanelPhotosManagement, {
+ global: {
+ plugins: [i18n, pinia],
+ mocks: {
+ $t: (msg) => msg
+ }
+ }
+ })
+ await wrapper.vm.triggerInputCheck({
+ isChecked: true,
+ isIndeterminate: false
+ })
+ expect(wrapper.emitted('triggerInputCheck')).toHaveLength(1)
+ expect(wrapper.emitted('triggerInputCheck')[0]).toEqual([
+ { isChecked: true, isIndeterminate: false }
+ ])
+ })
+ it('should emit triggerGoToNextPage event', async () => {
+ const wrapper = shallowMount(PanelPhotosManagement, {
+ global: {
+ plugins: [i18n, pinia],
+ mocks: {
+ $t: (msg) => msg
+ }
+ }
+ })
+ await wrapper.vm.triggerGoToNextPage('nextPage')
+ expect(wrapper.emitted('triggerGoToNextPage')).toHaveLength(1)
+ expect(wrapper.emitted('triggerGoToNextPage')[0]).toEqual(['nextPage'])
+ })
+
+ it('should emit triggerSelectImageAndMove event', async () => {
+ const wrapper = shallowMount(PanelPhotosManagement, {
+ global: {
+ plugins: [i18n, pinia],
+ mocks: {
+ $t: (msg) => msg
+ }
+ }
+ })
+ const picture = {
+ assets: { thumb: { href: 'thumbHref' }, hd: { href: 'hdHref' } },
+ properties: { datetime: new Date(), 'geovisio:status': 'ready' },
+ id: 'pictureId',
+ bbox: [1, 2, 3, 4]
+ }
+ await wrapper.vm.triggerSelectImageAndMove(picture)
+ expect(wrapper.emitted('triggerSelectImageAndMove')).toHaveLength(1)
+ expect(wrapper.emitted('triggerSelectImageAndMove')[0]).toEqual([picture])
+ })
+
+ it('should emit triggerPatchOrDeleteCollectionItems event', async () => {
+ const wrapper = shallowMount(PanelPhotosManagement, {
+ global: {
+ plugins: [i18n, pinia],
+ mocks: {
+ $t: (msg) => msg
+ }
+ }
+ })
+ await wrapper.vm.triggerPatchOrDeleteCollectionItems('itemToDelete')
+ expect(
+ wrapper.emitted('triggerPatchOrDeleteCollectionItems')
+ ).toHaveLength(1)
+ expect(wrapper.emitted('triggerPatchOrDeleteCollectionItems')[0]).toEqual(
+ ['itemToDelete']
+ )
+ })
+ })
+})
diff --git a/src/tests/unit/components/sequence/PanelSortManagement.spec.js b/src/tests/unit/components/sequence/PanelSortManagement.spec.js
new file mode 100644
index 0000000..cd00456
--- /dev/null
+++ b/src/tests/unit/components/sequence/PanelSortManagement.spec.js
@@ -0,0 +1,83 @@
+import { it, describe, expect } from 'vitest'
+import { shallowMount } from '@vue/test-utils'
+import PanelSortManagement from '../../../../components/sequence/PanelSortManagement.vue'
+import i18n from '../../config'
+
+describe('Template', () => {
+ describe('Props', () => {
+ it('should have default props', () => {
+ const wrapper = shallowMount(PanelSortManagement, {
+ global: {
+ plugins: [i18n],
+ mocks: {
+ $t: (msg) => msg
+ }
+ }
+ })
+
+ expect(wrapper.vm.sequenceSorted).toBe(null)
+ })
+ describe('When the component have props filled', () => {
+ it('should render the component all the element', () => {
+ const wrapper = shallowMount(PanelSortManagement, {
+ global: {
+ plugins: [i18n],
+ mocks: {
+ $t: (msg) => msg
+ }
+ }
+ })
+ expect(wrapper.html()).contains('pages.sequence.sort_panel_title')
+ expect(wrapper.html()).contains('pages.sequence.sort_panel_settings')
+ expect(wrapper.html()).contains(
+ 'name="sort" id="gpsdate" label="pages.sequence.sort_panel_check_gps" value=""'
+ )
+ expect(wrapper.html()).contains(
+ 'name="sort" id="filedate" label="pages.sequence.sort_panel_check_file" value=""'
+ )
+ expect(wrapper.html()).contains(
+ 'name="sort" id="filename" label="pages.sequence.sort_panel_check_name" value=""'
+ )
+ expect(wrapper.html()).contains(
+ 'pages.sequence.sort_panel_settings_order'
+ )
+ expect(wrapper.html()).contains('increased="true"> {
+ const wrapper = shallowMount(PanelSortManagement, {
+ global: {
+ plugins: [i18n],
+ mocks: {
+ $t: (msg) => msg
+ }
+ },
+ props: {
+ sequenceSorted: '-gpsdate'
+ }
+ })
+ expect(wrapper.html()).contains(
+ 'name="sort" id="gpsdate" label="pages.sequence.sort_panel_check_gps" value="gpsdate"'
+ )
+ expect(wrapper.html()).contains('increased="false"> {
+ it('should emit triggerSort event', async () => {
+ const wrapper = shallowMount(PanelSortManagement, {
+ global: {
+ plugins: [i18n],
+ mocks: {
+ $t: (msg) => msg
+ }
+ },
+ props: {
+ sequenceSorted: '-gpsdate'
+ }
+ })
+ await wrapper.vm.triggerSort('-gpsdate')
+ expect(wrapper.emitted('triggerSort')).toHaveLength(1)
+ expect(wrapper.emitted('triggerSort')[0]).toEqual(['-gpsdate'])
+ })
+ })
+})
diff --git a/src/tests/unit/components/sequence/WidgetOrientation.spec.js b/src/tests/unit/components/sequence/WidgetOrientation.spec.js
new file mode 100644
index 0000000..dc88e59
--- /dev/null
+++ b/src/tests/unit/components/sequence/WidgetOrientation.spec.js
@@ -0,0 +1,53 @@
+import { it, describe, expect } from 'vitest'
+import { shallowMount } from '@vue/test-utils'
+import WidgetOrientation from '../../../../components/sequence/WidgetOrientation.vue'
+import i18n from '../../config'
+
+describe('Template', () => {
+ describe('Props', () => {
+ it('should have default props', () => {
+ const wrapper = shallowMount(WidgetOrientation, {
+ global: {
+ plugins: [i18n],
+ mocks: {
+ $t: (msg) => msg
+ }
+ }
+ })
+
+ expect(wrapper.vm.roadDegrees).toBe(0)
+ expect(wrapper.vm.seqBruteDeg).toBe(0)
+ })
+ describe('When the component have props filled', () => {
+ it('should render the component all the element', () => {
+ const wrapper = shallowMount(WidgetOrientation, {
+ global: {
+ plugins: [i18n],
+ mocks: {
+ $t: (msg) => msg
+ }
+ },
+ props: {
+ roadDegrees: 45,
+ seqBruteDeg: 22
+ }
+ })
+ expect(wrapper.html()).contains(
+ 'class="wrapper-img-road" style="transform: rotate(45deg);"'
+ )
+ expect(wrapper.html()).contains(
+ 'src="/assets/images/car.svg" alt="" style="transform: rotate(45deg);" class="car-img"'
+ )
+ expect(wrapper.html()).contains(
+ 'style="transform: rotate(22deg);" id="rotateWrapper" class="rotate-wrapper"'
+ )
+ expect(wrapper.html()).contains(
+ 'src="/assets/images/icon/cursor-arrow.svg"'
+ )
+ expect(wrapper.html()).contains('class="arrow-img arrow-img-1"')
+ expect(wrapper.html()).contains('class="arrow-img arrow-img-2"')
+ })
+ })
+ })
+ // TODO TEST -> All Events
+})
diff --git a/src/utils/mapAndViewer.ts b/src/utils/mapAndViewer.ts
new file mode 100644
index 0000000..db76efa
--- /dev/null
+++ b/src/utils/mapAndViewer.ts
@@ -0,0 +1,29 @@
+import axios from 'axios'
+
+async function getIgnTiles(): Promise {
+ try {
+ const { data } = await axios.get(
+ 'https://wxs.ign.fr/essentiels/static/vectorTiles/styles/PLAN.IGN/attenue.json'
+ )
+ data.sources.plan_ign.scheme = 'xyz'
+ data.sources.plan_ign.attribution = 'Données cartographiques : © IGN'
+ const objIndex = data.layers.findIndex(
+ (el: { id: string }) => el.id === 'toponyme - parcellaire - adresse'
+ )
+ data.layers[objIndex].layout = {
+ ...data.layers[objIndex].layout,
+ 'text-field': [
+ 'concat',
+ ['get', 'numero'],
+ ['get', 'indice_de_repetition']
+ ]
+ }
+ // Patch tms scheme to xyz to make it compatible for Maplibre GL JS / Mapbox GL JS
+ // Patch num_repetition
+ return data
+ } catch (error) {
+ return 'https://tile-vect.openstreetmap.fr/styles/basic/style.json'
+ }
+}
+
+export { getIgnTiles }
diff --git a/src/views/MySequenceView.vue b/src/views/MySequenceView.vue
index 6dc31d4..27bc896 100644
--- a/src/views/MySequenceView.vue
+++ b/src/views/MySequenceView.vue
@@ -20,16 +20,25 @@
icon="bi bi-arrow-left"
:text="$t('pages.sequence.back_button')"
:route="{ name: 'my-sequences' }"
- look="link--grey"
+ look="link--grey-dark"
/>
+
+
+
+
+