diff --git a/.github/workflows/Branch-protection.yml b/.github/workflows/Branch-protection.yml deleted file mode 100644 index bd471369..00000000 --- a/.github/workflows/Branch-protection.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: Check branch origin - -on: - pull_request: - -jobs: - check-branch-protection: - uses: Geode-solutions/actions/.github/workflows/branch-protection.yml@master - with: - branch_from: "next" - branch_to: "master" diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml deleted file mode 100644 index 9c0b4749..00000000 --- a/.github/workflows/CICD.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: CICD - -on: - push: - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Unit tests - run: | - npm ci - npm run test - - build: - runs-on: ubuntu-latest - needs: test - if: github.ref == 'refs/heads/next' || github.ref == 'refs/heads/master' - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Semantic Release - uses: cycjimmy/semantic-release-action@v3 - id: semantic - env: - GITHUB_TOKEN: ${{ secrets.TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - name: Merge master -> next - if: github.ref == 'refs/heads/master' - uses: devmasx/merge-branch@master - with: - type: now - from_branch: master - target_branch: next - github_token: ${{ secrets.TOKEN }} diff --git a/.github/workflows/pr_update.yml b/.github/workflows/pr_update.yml new file mode 100644 index 00000000..fd9d76ee --- /dev/null +++ b/.github/workflows/pr_update.yml @@ -0,0 +1,11 @@ +name: Pull request + +on: + pull_request: + types: [opened, reopened] + branches: + - master + +jobs: + update-branch: + uses: Geode-solutions/actions/.github/workflows/update-branch.yml@master diff --git a/.github/workflows/prepare_pr.yml b/.github/workflows/prepare_pr.yml deleted file mode 100644 index d02abb35..00000000 --- a/.github/workflows/prepare_pr.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: Prepare PR - -on: - pull_request: - branches: - - next - -jobs: - prepare: - uses: Geode-solutions/actions/.github/workflows/web-prepare-pr.yml@master - secrets: inherit diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..943798b5 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,14 @@ +name: Test + +on: + push: + branches-ignore: + - master + - next + +jobs: + test: + uses: Geode-solutions/actions/.github/workflows/js-test.yml@master + with: + repos: ${{ vars.REPOS }} + secrets: inherit diff --git a/.github/workflows/test_pr.yml b/.github/workflows/test_pr.yml new file mode 100644 index 00000000..b9d9425e --- /dev/null +++ b/.github/workflows/test_pr.yml @@ -0,0 +1,12 @@ +name: Test PR + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +jobs: + test: + uses: Geode-solutions/actions/.github/workflows/js-test-pr.yml@master + with: + repos: ${{ vars.REPOS }} + secrets: inherit diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 00000000..79c1bdc1 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,11 @@ +{ + "categories": { + "correctness": "error", + "suspicious": "error", + "pedantic": "warn", + "perf": "error", + "style": "error", + "restriction": "error" + }, + "plugins": ["import", "node", "oxc", "promise", "unicorn", "vitest"] +} diff --git a/.releaserc b/.releaserc index 37dc70c2..bf47fdf5 100644 --- a/.releaserc +++ b/.releaserc @@ -6,7 +6,6 @@ plugins: [ '@semantic-release/commit-analyzer', '@semantic-release/release-notes-generator', - '@semantic-release/github', - '@semantic-release/npm' + '@semantic-release/github' ] } diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 00000000..3a29484e --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,16 @@ +export default { + extends: ["@commitlint/config-angular"], + rules: { + "scope-empty": [2, "never"], + "subject-empty": [2, "never"], + "subject-max-length": [0], + "body-leading-blank": [0], + "footer-leading-blank": [0], + "header-max-length": [0], + "scope-case": [0], + "subject-case": [0], + "subject-full-stop": [0], + "type-case": [0], + "type-empty": [0], + }, +} diff --git a/components/ObjectSelector.vue b/components/ObjectSelector.vue index a6b09fc8..72e05618 100644 --- a/components/ObjectSelector.vue +++ b/components/ObjectSelector.vue @@ -24,7 +24,7 @@ @@ -66,44 +66,81 @@ const allowed_objects = ref({}) const toggle_loading = useToggle(loading) + function select_geode_object(object_map) { + const object_keys = Object.keys(object_map) + if (!object_keys.length) { + return undefined + } + if ( + object_keys.length === 1 && + object_map[object_keys[0]].is_loadable > 0 + ) { + return object_keys[0] + } + const highest_load_score = Math.max( + ...object_keys.map((key) => object_map[key].is_loadable), + ) + if (highest_load_score <= 0) { + return undefined + } + const best_score_objects = object_keys.filter( + (key) => object_map[key].is_loadable === highest_load_score, + ) + if (best_score_objects.length === 1) { + return best_score_objects[0] + } + const highest_priority = Math.max( + ...best_score_objects.map( + (key) => object_map[key].object_priority ?? -Infinity, + ), + ) + const best_priority_objects = best_score_objects.filter( + (key) => object_map[key].object_priority === highest_priority, + ) + if (highest_priority !== -Infinity && best_priority_objects.length === 1) { + return best_priority_objects[0] + } + return undefined + } + async function get_allowed_objects() { toggle_loading() allowed_objects.value = {} - var promise_array = [] - for (const filename of filenames) { + const promise_array = filenames.map((filename) => { const params = { filename, supported_feature } - const promise = api_fetch({ schema, params }) - promise_array.push(promise) - } + return api_fetch({ schema, params }) + }) const responses = await Promise.all(promise_array) - let values = [] - for (const response of responses) { - values.push(response.data.value.allowed_objects) - } - const all_keys = [...new Set(values.flatMap((value) => Object.keys(value)))] - const common_keys = all_keys.filter( - (i) => !values.some((j) => !Object.keys(j).includes(i)), + const allowed_objects_list = responses.map( + (response) => response.data.value.allowed_objects, + ) + const all_keys = [...new Set(allowed_objects_list.flatMap(Object.keys))] + const common_keys = all_keys.filter((key) => + allowed_objects_list.every((obj) => key in obj), ) - var final_object = {} + const final_object = {} for (const key of common_keys) { - for (const value of values) { - if (value[key].is_loadable == false) { - final_object[key] = { is_loadable: false } - } else { - final_object[key] = { is_loadable: true } - } + const load_scores = allowed_objects_list.map( + (obj) => obj[key].is_loadable, + ) + const priorities = allowed_objects_list + .map((obj) => obj[key].object_priority) + .filter((p) => p !== undefined && p !== null) + final_object[key] = { is_loadable: Math.min(...load_scores) } + if (priorities.length) { + final_object[key].object_priority = Math.max(...priorities) } } - allowed_objects.value = final_object - if (Object.keys(allowed_objects.value).length == 1) { - set_geode_object(Object.keys(allowed_objects.value)[0]) + const selected_object = select_geode_object(final_object) + if (selected_object) { + set_geode_object(selected_object) } toggle_loading() } function set_geode_object(input_geode_object) { - if (input_geode_object != "") { + if (input_geode_object) { emit("update_values", { input_geode_object }) emit("increment_step") } diff --git a/components/ContextMenu.vue b/components/Viewer/ContextMenu.vue similarity index 100% rename from components/ContextMenu.vue rename to components/Viewer/ContextMenu.vue diff --git a/components/ContextMenuItem.vue b/components/Viewer/ContextMenuItem.vue similarity index 100% rename from components/ContextMenuItem.vue rename to components/Viewer/ContextMenuItem.vue diff --git a/internal_stores/mesh/index.js b/internal_stores/mesh/index.js index e827a75c..b65966bd 100644 --- a/internal_stores/mesh/index.js +++ b/internal_stores/mesh/index.js @@ -10,6 +10,7 @@ export default function useMeshStyle() { const edgesStyleStore = useMeshEdgesStyle() const polygonsStyleStore = useMeshPolygonsStyle() const polyhedraStyleStore = useMeshPolyhedraStyle() + const hybridViewerStore = useHybridViewerStore() function setMeshVisibility(id, visibility) { viewer_call( @@ -20,6 +21,7 @@ export default function useMeshStyle() { { response_function: () => { dataStyleStore.styles[id].visibility = visibility + hybridViewerStore.setVisibility(id, visibility) console.log("setMeshVisibility", dataStyleStore.styles[id].visibility) }, }, diff --git a/internal_stores/model/index.js b/internal_stores/model/index.js index 93a3b403..c4360267 100644 --- a/internal_stores/model/index.js +++ b/internal_stores/model/index.js @@ -16,6 +16,7 @@ export default function useModelStyle() { const blocksStyleStore = useBlocksStyle() const modelEdgesStore = useModelEdgesStyle() const modelPointsStore = useModelPointsStyle() + const hybridViewerStore = useHybridViewerStore() /** Getters **/ function modelVisibility(id) { @@ -70,6 +71,7 @@ export default function useModelStyle() { { response_function: () => { dataStyleStore.styles[id].visibility = visibility + hybridViewerStore.setVisibility(id, visibility) console.log("setModelVisibility", visibility) }, }, diff --git a/package-lock.json b/package-lock.json index e1d50e39..7b35712e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@geode/opengeodeweb-front", - "version": "0.0.0-semantically-released", + "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@geode/opengeodeweb-front", - "version": "0.0.0-semantically-released", + "version": "0.0.0", "license": "MIT", "dependencies": { "@geode/opengeodeweb-back": "5.8.7", diff --git a/package.json b/package.json index 65cf9853..f3afded1 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "lint": "eslint --fix --ext .js,.vue --ignore-path .gitignore .", "test": "vitest", "coverage": "vitest run --coverage", - "geode_objects": "node scripts/generate_geode_objects.js && prettier ./assets/geode_objects.js --write" + "geode_objects": "node scripts/generate_geode_objects.js && prettier ./assets/geode_objects.js --write", + "build": "" }, "devDependencies": { "@nuxt/test-utils": "3.18.0", @@ -34,11 +35,11 @@ }, "description": "OpenSource Vue/Vuetify framework for web applications", "type": "module", - "version": "0.0.0-semantically-released", + "version": "0.0.0", "main": "./nuxt.config.js", "dependencies": { - "@geode/opengeodeweb-back": "5.8.7", - "@geode/opengeodeweb-viewer": "1.10.1", + "@geode/opengeodeweb-back": "latest", + "@geode/opengeodeweb-viewer": "latest", "@kitware/vtk.js": "33.3.0", "@mdi/font": "7.4.47", "@pinia/nuxt": "0.5.4", diff --git a/stores/data_base.js b/stores/data_base.js index 4e836046..c8751e05 100644 --- a/stores/data_base.js +++ b/stores/data_base.js @@ -74,6 +74,7 @@ export const useDataBaseStore = defineStore("dataBase", () => { { schema: back_schemas.opengeodeweb_back.models.mesh_components, params: { + id, filename: native_filename, geode_object, }, diff --git a/stores/hybrid_viewer.js b/stores/hybrid_viewer.js index 75a2e017..43e8d099 100644 --- a/stores/hybrid_viewer.js +++ b/stores/hybrid_viewer.js @@ -66,6 +66,11 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => { db[id] = { actor, polydata, mapper } } + async function setVisibility(id, visibility) { + db[id].actor.setVisibility(visibility) + const renderWindow = genericRenderWindow.value.getRenderWindow() + renderWindow.render() + } async function setZScaling(z_scale) { zScale.value = z_scale const renderer = genericRenderWindow.value.getRenderer() @@ -183,6 +188,7 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => { db, genericRenderWindow, addItem, + setVisibility, setZScaling, syncRemoteCamera, initHybridViewer, diff --git a/test/components/ObjectSelector.nuxt.test.js b/test/components/ObjectSelector.nuxt.test.js index 91b8001a..f6fb9369 100644 --- a/test/components/ObjectSelector.nuxt.test.js +++ b/test/components/ObjectSelector.nuxt.test.js @@ -83,4 +83,33 @@ describe("ObjectSelector.vue", async () => { input_geode_object: geode_object_1, }) }) + + test(`test object_priority when is_loadable scores equal`, async () => { + var response = { allowed_objects: {} } + const geode_object_1 = "BRep" + const geode_object_2 = "EdgedCurve3D" + response["allowed_objects"][geode_object_1] = { + is_loadable: 1.0, + object_priority: 2, + } + response["allowed_objects"][geode_object_2] = { + is_loadable: 1.0, + object_priority: 1, + } + registerEndpoint(allowed_objects.$id, { + method: allowed_objects.methods[0], + handler: () => response, + }) + const wrapper = await mountSuspended(ObjectSelector, { + global: { + plugins: [vuetify, pinia], + }, + props: { filenames: ["test.toto"], supported_feature: "test" }, + }) + expect(wrapper.emitted()).toHaveProperty("update_values") + expect(wrapper.emitted().update_values).toHaveLength(1) + expect(wrapper.emitted().update_values[0][0]).toEqual({ + input_geode_object: geode_object_1, + }) + }) }) diff --git a/test/components/Stepper.nuxt.test.js b/test/components/Stepper.nuxt.test.js index 36c81c83..0f8af9c3 100644 --- a/test/components/Stepper.nuxt.test.js +++ b/test/components/Stepper.nuxt.test.js @@ -1,5 +1,4 @@ import { describe, expect, test } from "vitest" -import { mountSuspended } from "@vue/test-utils" import { createVuetify } from "vuetify" import * as components from "vuetify/components"