Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 69 additions & 7 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,96 @@
"style": "error",
"restriction": "error"
},
"plugins": ["import", "node", "oxc", "promise", "unicorn", "vitest"],
"plugins": ["import", "node", "oxc", "promise", "unicorn", "vitest", "vue"],
"rules": {
"unicorn/filename-case": [
"error",
{
"case": "snakeCase"
}
],
"eslint/func-style": [
"eslint/func-style": ["error", "declaration"],
"eslint/sort-keys": "off",
"eslint/no-ternary": "off", // A utiliser pour des opérations simples
"oxc/no-async-await": "off",
"oxc/no-rest-spread-properties": "off", // Enable if older browser support is needed
"eslint/max-statements": ["warn", 20],
"eslint/id-length": [
"error",
{
"style:": "declaration"
"exceptions": [
"x",
"y",
"z",
"i",
"j",
"k",
"r",
"g",
"b",
"id",
"ID",
"fs",
"os"
],
"min": 3
}
],
"eslint/sort-keys": "off",
"eslint/no-ternary": "off"
"eslint/no-console": "warn", // Disable for debugging. Disable later to not have browser logs
"sort-imports": ["error", { "allowSeparatedGroups": true }],
"eslint/no-undefined": "off", // Conflict with unicorn/no-typeof-undefined which prefers direct undefined comparison
"import/prefer-default-export": "off",
"import/no-named-export": "off",
"import/no-namespace": ["error", { "ignore": ["vuetify/*"] }],
"vue/max-props": ["error", { "maxProps": 8 }],
"oxc/no-optional-chaining": "off",
"node/no-process-env": "off",
"no-continue": "off",
"import/unambiguous": "off",
"max-params": ["warn", { "max": 4 }],
"eslint/no-magic-numbers": [
"error",
{
"ignore": [-1, 0, 1, 2, 3, 4],
"ignoreArrayIndexes": true
}
]
},
"overrides": [
{
"files": ["**/components/*"],
"files": ["**/components/**"],
"rules": {
"unicorn/filename-case": [
"error",
{
"case": "PascalCase"
"case": "pascalCase"
}
]
}
},
{
"files": [
"app/plugins/**",
"node_scripts/**",
"server/**",
"*.config.js"
],
"rules": {
"import/no-default-export": "off"
}
},
{
"files": ["tests/**"],
"rules": {
"vitest/require-hook": "off",
"vitest/no-hooks": "off"
}
},
{
"files": ["**/preload.js"],
"rules": {
"import/no-commonjs": "off"
}
}
]
}
2 changes: 1 addition & 1 deletion app/components/Viewer/BreadCrumb.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

const model_id = computed(() => treeviewStore.model_id)

const metaDatas = computed(() => dataStore.getItem(model_id.value).value)
const metaDatas = dataStore.refItem(model_id.value)
</script>

<template>
Expand Down
10 changes: 1 addition & 9 deletions app/components/Viewer/ContextMenu.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script setup>
import { useDataStore } from "@ogw_front/stores/data"
import { useEventListener } from "@vueuse/core"
import { useMenuStore } from "@ogw_front/stores/menu"

Expand All @@ -16,7 +15,6 @@
const CLOSE_DELAY = 100

const menuStore = useMenuStore()
const dataStore = useDataStore()

const { id, x, y, containerWidth, containerHeight } = defineProps({
id: { type: String, required: true },
Expand All @@ -26,13 +24,7 @@
containerHeight: { type: Number, required: true },
})

const meta_data = computed(() => {
const itemId = id || menuStore.current_id
if (!itemId) {
return {}
}
return dataStore.getItem(itemId).value || {}
})
const meta_data = computed(() => menuStore.current_meta_data || {})

const show_menu = ref(true)
const isDragging = ref(false)
Expand All @@ -44,7 +36,7 @@
watch(
() => [x, y],
([newX, newY]) => {
const { x, y } = clampPosition(newX, newY)

Check failure on line 39 in app/components/Viewer/ContextMenu.vue

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(no-shadow)

'y' is already declared in the upper scope.

Check failure on line 39 in app/components/Viewer/ContextMenu.vue

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(no-shadow)

'x' is already declared in the upper scope.
menuX.value = x
menuY.value = y
menuStore.setMenuPosition(x, y)
Expand Down Expand Up @@ -89,7 +81,7 @@
event.preventDefault()
}

function clampPosition(x, y) {

Check failure on line 84 in app/components/Viewer/ContextMenu.vue

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(no-shadow)

'y' is already declared in the upper scope.

Check failure on line 84 in app/components/Viewer/ContextMenu.vue

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(no-shadow)

'x' is already declared in the upper scope.
const margin = RADIUS + MARGIN_OFFSET
return {
x: Math.min(Math.max(x, margin), containerWidth - margin),
Expand All @@ -98,7 +90,7 @@
}

function handleDrag(event) {
const { x, y } = clampPosition(

Check failure on line 93 in app/components/Viewer/ContextMenu.vue

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(no-shadow)

'y' is already declared in the upper scope.

Check failure on line 93 in app/components/Viewer/ContextMenu.vue

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(no-shadow)

'x' is already declared in the upper scope.
event.clientX - dragStartX.value,
event.clientY - dragStartY.value,
)
Expand Down
16 changes: 9 additions & 7 deletions app/stores/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,192 +12,194 @@
const back_model_schemas = back_schemas.opengeodeweb_back.models
const viewer_generic_schemas = viewer_schemas.opengeodeweb_viewer.generic

export const useDataStore = defineStore("data", () => {
const viewerStore = useViewerStore()

function getItem(id) {
if (!id) {
return ref({})
}
function item(id) {
return database.data.get(id)
}

function refItem(id) {
return useObservable(
liveQuery(() => database.data.get(id)),
{ initialValue: {} },
)
}

function getAllItems() {
function refAllItems() {
return useObservable(
liveQuery(() => database.data.toArray()),
{ initialValue: [] },
)
}

async function formatedMeshComponents(id) {
const items = await database.model_components.where({ id }).toArray()
const componentTitles = {
Corner: "Corners",
Line: "Lines",
Surface: "Surfaces",
Block: "Blocks",
}

const componentsByType = items.reduce((accumulator, item) => {
if (componentTitles[item.type]) {
if (!accumulator[item.type]) accumulator[item.type] = []
accumulator[item.type].push(item)
}
return accumulator
}, {})

return Object.keys(componentTitles)
.filter((type) => componentsByType[type])
.map((type) => ({
id: type,
title: componentTitles[type],
children: componentsByType[type].map((meshComponent) => ({
id: meshComponent.geode_id,
title: meshComponent.name,
category: meshComponent.type,
})),
}))
}

async function meshComponentType(id, geode_id) {
const component = await database.model_components
.where({ id, geode_id })
.first()
return component?.type
}

async function registerObject(id) {
return await viewerStore.request(viewer_generic_schemas.register, { id })
}

async function deregisterObject(id) {
return await viewerStore.request(viewer_generic_schemas.deregister, { id })
}

async function addItem(id, value) {
const itemData = {
...value,
id,
name: value.name || id,
geode_object_type: value.geode_object_type,
visible: value.visible !== undefined ? value.visible : true,
created_at: value.created_at || new Date().toISOString(),
}

const serializedData = structuredClone(itemData)
await database.data.put(serializedData)
}
async function deleteItem(id) {
await database.data.delete(id)
await deleteModelComponents(id)
}
async function updateItem(id, changes) {
await database.data.update(id, changes)
}

async function addModelComponents(values) {
if (!values || values.length === 0) {
console.debug("[addModelComponents] No mesh components to add")
return
}
for (const value of values) {
value.created_at = new Date().toISOString()
}
const serializedData = structuredClone(values)
await database.model_components.bulkAdd(serializedData)
}

async function deleteModelComponents(id) {
await database.model_components.where({ id }).delete()
}

async function fetchModelComponents(id) {
const geodeStore = useGeodeStore()
return await geodeStore.request(
back_model_schemas.model_components,
{ id },
{
response_function: async (response) => {
const allComponents = [
...response.mesh_components.map(
({ boundaries, internals, ...component }) => component,
),
...response.collection_components.map(
({ items, ...component }) => component,
),
].map((component) => ({ ...component, id }))
await addModelComponents(allComponents)
},
},
)
}

async function getMeshComponentGeodeIds(id, meshComponentType) {
const components = await database.model_components
.where({ id, type: meshComponentType })
.toArray()
return components.map((component) => component.geode_id)
}

async function getCornersGeodeIds(id) {
return await getMeshComponentGeodeIds(id, "Corner")
}

async function getLinesGeodeIds(id) {
return await getMeshComponentGeodeIds(id, "Line")
}

async function getSurfacesGeodeIds(id) {
return await getMeshComponentGeodeIds(id, "Surface")
}

async function getBlocksGeodeIds(id) {
return await getMeshComponentGeodeIds(id, "Block")
}

async function getMeshComponentsViewerIds(id, meshComponentGeodeIds) {
const components = await database.model_components
.where("id")
.equals(id)
.and((component) => meshComponentGeodeIds.includes(component.geode_id))
.toArray()
return components.map((component) => component.viewer_id)
}

async function exportStores() {
const items = await database.data.toArray()
return { items }
}

async function importStores(_snapshot) {
await clear()
}

async function clear() {
await database.data.clear()
}

return {
getAllItems,
getItem,
refAllItems,
item,
refItem,
meshComponentType,
formatedMeshComponents,
registerObject,
deregisterObject,
addItem,
deleteItem,
updateItem,
fetchModelComponents,
getCornersGeodeIds,
getLinesGeodeIds,
getSurfacesGeodeIds,
getBlocksGeodeIds,
getMeshComponentsViewerIds,
exportStores,
importStores,
clear,
}
})

Check warning on line 205 in app/stores/data.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(max-lines-per-function)

The function has too many lines (191). Maximum allowed is 50.
4 changes: 2 additions & 2 deletions app/stores/data_style.js
Original file line number Diff line number Diff line change
@@ -1,94 +1,94 @@
import { getDefaultStyle } from "@ogw_front/utils/default_styles"
import { database } from "../../internal/database/database.js"

Check failure on line 2 in app/stores/data_style.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint-plugin-import(no-relative-parent-imports)

Relative imports from parent directories are not allowed
import { useDataStore } from "@ogw_front/stores/data"
import { useDataStyleStateStore } from "../../internal/stores/data_style/state"

Check failure on line 4 in app/stores/data_style.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint-plugin-import(no-relative-parent-imports)

Relative imports from parent directories are not allowed
import useMeshStyle from "../../internal/stores/data_style/mesh/index"

Check failure on line 5 in app/stores/data_style.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint-plugin-import(no-relative-parent-imports)

Relative imports from parent directories are not allowed
import useModelStyle from "../../internal/stores/data_style/model/index"

Check failure on line 6 in app/stores/data_style.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint-plugin-import(no-relative-parent-imports)

Relative imports from parent directories are not allowed

export const useDataStyleStore = defineStore("dataStyle", () => {
const dataStyleState = useDataStyleStateStore()
const meshStyleStore = useMeshStyle()
const modelStyleStore = useModelStyle()
const dataStore = useDataStore()

function addDataStyle(id, geode_object) {
dataStyleState.styles[id] = getDefaultStyle(geode_object)
}

async function setVisibility(id, visibility) {
const item = await database.data.get(id)
const viewer_type = item?.viewer_type
if (!viewer_type) {
throw new Error(`Item not found or not loaded: ${id}`)
}

if (viewer_type === "mesh") {
return meshStyleStore.setMeshVisibility(id, visibility)
}
if (viewer_type === "model") {
return modelStyleStore.setModelVisibility(id, visibility)
}
throw new Error("Unknown viewer_type")
}

async function applyDefaultStyle(id) {
const item = await database.data.get(id)
const viewer_type = item?.viewer_type
if (!viewer_type) {
throw new Error(`Item not found or not loaded: ${id}`)
}

if (viewer_type === "mesh") {
return meshStyleStore.applyMeshStyle(id)
}
if (viewer_type === "model") {
return modelStyleStore.applyModelStyle(id)
}
throw new Error(`Unknown viewer_type: ${viewer_type}`)
}

function exportStores() {
return { styles: dataStyleState.styles }
}

function importStores(snapshot) {
const stylesSnapshot = snapshot.styles || {}
for (const id of Object.keys(dataStyleState.styles)) {
delete dataStyleState.styles[id]
}
for (const [id, style] of Object.entries(stylesSnapshot)) {
dataStyleState.styles[id] = style
}
}

function applyAllStylesFromState() {
async function applyAllStylesFromState() {
const ids = Object.keys(dataStyleState.styles || {})
const promises = []
for (const id of ids) {
const meta = dataStore.getItem(id).value
const meta = await dataStore.item(id)
const viewerType = meta?.viewer_type
const style = dataStyleState.styles[id]
if (style && viewerType === "mesh") {
promises.push(meshStyleStore.applyMeshStyle(id))
} else if (style && viewerType === "model") {
promises.push(modelStyleStore.applyModelStyle(id))
}
}
return Promise.all(promises)
}

return {
styles: dataStyleState.styles,
getStyle: dataStyleState.getStyle,
objectVisibility: dataStyleState.objectVisibility,
selectedObjects: dataStyleState.selectedObjects,
...meshStyleStore,
...modelStyleStore,
addDataStyle,
applyDefaultStyle,
setVisibility,
exportStores,
importStores,
applyAllStylesFromState,
}
})

Check warning on line 94 in app/stores/data_style.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(max-lines-per-function)

The function has too many lines (87). Maximum allowed is 50.
4 changes: 4 additions & 0 deletions app/stores/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

// Grid 2D components
import Grid2DCellsOptions from "@ogw_front/components/Viewer/Grid/2D/CellsOptions"
import Grid2DEdgesOptions from "@ogw_front/components/Viewer/Grid/2D/EdgesOptions"

Check warning on line 20 in app/stores/menu.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint-plugin-import(max-dependencies)

File has too many dependencies (23). Maximum allowed is 10.
import Grid2DPointsOptions from "@ogw_front/components/Viewer/Grid/2D/PointsOptions"

// Grid 3D components
Expand Down Expand Up @@ -121,34 +121,36 @@
},
}

export const useMenuStore = defineStore("menu", () => {
const menus = shallowRef(menusData)
const display_menu = ref(false)
const current_id = ref(undefined)
const menuX = ref(0)
const menuY = ref(0)
const containerWidth = ref(window.innerWidth)
const containerHeight = ref(window.innerHeight)
const containerTop = ref(0)
const containerLeft = ref(0)
const active_item_index = ref(undefined)
const current_meta_data = ref({})

function getMenuItems(objectType, geodeObject) {
if (!objectType || !geodeObject || !menus.value[objectType]) {
return []
}
return menus.value[objectType][geodeObject] || []
}

function closeMenu() {
active_item_index.value = undefined
current_id.value = undefined
current_meta_data.value = {}
menuX.value = 0
menuY.value = 0
display_menu.value = false
}

async function openMenu(id, x, y, width, height, top, left, meta_data) {

Check warning on line 153 in app/stores/menu.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(max-params)

Function 'openMenu' has too many parameters (8). Maximum allowed is 4.
await closeMenu()

if (meta_data) {
Expand All @@ -162,6 +164,7 @@
}

current_id.value = id
current_meta_data.value = meta_data || {}

if (x !== undefined && y !== undefined) {
menuX.value = x
Expand Down Expand Up @@ -202,6 +205,7 @@
return {
display_menu,
current_id,
current_meta_data,
menuX,
menuY,
containerWidth,
Expand Down
6 changes: 3 additions & 3 deletions internal/stores/data_style/model/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,35 @@
import { useModelLinesStyle } from "./lines"
import { useModelPointsStyle } from "./points"
import { useModelSurfacesStyle } from "./surfaces"
import { useViewerStore } from "@ogw_front/stores/viewer"

Check warning on line 14 in internal/stores/data_style/model/index.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint-plugin-import(max-dependencies)

File has too many dependencies (11). Maximum allowed is 10.

// Local constants
const model_schemas = viewer_schemas.opengeodeweb_viewer.model

export default function useModelStyle() {
const dataStore = useDataStore()
const dataStyleStateStore = useDataStyleStateStore()
const modelCornersStyleStore = useModelCornersStyle()
const modelBlocksStyleStore = useModelBlocksStyle()
const modelEdgesStyleStore = useModelEdgesStyle()
const modelLinesStyleStore = useModelLinesStyle()
const modelPointsStyleStore = useModelPointsStyle()
const modelSurfacesStyleStore = useModelSurfacesStyle()
const hybridViewerStore = useHybridViewerStore()
const viewerStore = useViewerStore()

function modelVisibility(id) {
return dataStyleStateStore.getStyle(id).visibility
}
function setModelVisibility(id, visibility) {
return viewerStore.request(
model_schemas.visibility,
{ id, visibility },
{
response_function: () => {
dataStyleStateStore.getStyle(id).visibility = visibility
hybridViewerStore.setVisibility(id, visibility)
console.log(setModelVisibility.name, { id }, modelVisibility(id))

Check warning on line 42 in internal/stores/data_style/model/index.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(no-console)

Unexpected console statement.
},
},
)
Expand Down Expand Up @@ -102,7 +102,7 @@
{
response_function: () => {
dataStyleStateStore.styles[id].color = color
console.log(setModelColor.name, { id }, modelColor(id))

Check warning on line 105 in internal/stores/data_style/model/index.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(no-console)

Unexpected console statement.
},
},
)
Expand Down Expand Up @@ -136,11 +136,11 @@
visibility,
)
} else if (component_type === "Block") {
return modelBlocksStyleStore.setModelBlocksVisibility(
id,
component_geode_ids,
visibility,
)

Check warning on line 143 in internal/stores/data_style/model/index.js

View workflow job for this annotation

GitHub Actions / test / oxlint

eslint(no-else-return)

Unnecessary `else` after `return`.
} else {
throw new Error(`Unknown model component_type: ${component_type}`)
}
Expand Down Expand Up @@ -171,9 +171,9 @@
return Promise.all(promise_array)
}

function setModelMeshComponentsDefaultStyle(id) {
const item = dataStore.getItem(id)
const { mesh_components } = item.value
async function setModelMeshComponentsDefaultStyle(id) {
const item = await dataStore.item(id)
const { mesh_components } = item
const promise_array = []
if ("Corner" in mesh_components) {
promise_array.push(modelCornersStyleStore.setModelCornersDefaultStyle(id))
Expand Down
1 change: 0 additions & 1 deletion tests/integration/microservices/back/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@
# pip-compile --output-file=tests/integration/microservices/back/requirements.txt tests/integration/microservices/back/requirements.in
#

opengeodeweb-back==6.*,>=6.2.0rc2
1 change: 0 additions & 1 deletion tests/integration/microservices/viewer/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@
# pip-compile --output-file=tests/integration/microservices/viewer/requirements.txt tests/integration/microservices/viewer/requirements.in
#

opengeodeweb-viewer==1.*,>=1.15.4rc1