Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e455c5f
save wip [skip ci]
JulienChampagnol Jul 21, 2026
0720d3d
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
JulienChampagnol Jul 22, 2026
2312492
[skip ci}
JulienChampagnol Jul 22, 2026
0b68e29
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
JulienChampagnol Jul 23, 2026
e00fb6b
save wip [skip ci]
JulienChampagnol Jul 27, 2026
3cd2381
save wip [skip ci]
JulienChampagnol Jul 27, 2026
a7eabc0
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
JulienChampagnol Jul 28, 2026
b242cf0
save wip [skip ci]
JulienChampagnol Jul 28, 2026
4bb0ea4
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
JulienChampagnol Jul 29, 2026
ce2cc96
pull [skip ci]
JulienChampagnol Jul 29, 2026
488b1d9
save wip [skip ci]
JulienChampagnol Jul 30, 2026
f59ef89
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
JulienChampagnol Jul 30, 2026
aa8fdda
cleanup [skip ci]
JulienChampagnol Jul 30, 2026
c072de8
cleanup [skip ci]
JulienChampagnol Jul 30, 2026
1a953cb
cleanup [skip ci]
JulienChampagnol Jul 31, 2026
8a5b6d9
v0 working
JulienChampagnol Jul 31, 2026
625287c
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
JulienChampagnol Jul 31, 2026
f027995
fix(Refactor): refactor functions in shared
JulienChampagnol Jul 31, 2026
d3f5329
Apply prepare changes
JulienChampagnol Jul 31, 2026
4105b30
pr comments + oxlint [skip ci]
JulienChampagnol Jul 31, 2026
8a47ae7
pr comments + oxlint [skip ci]
JulienChampagnol Jul 31, 2026
4ed2928
trigger tests
JulienChampagnol Jul 31, 2026
9b08756
Apply prepare changes
JulienChampagnol Jul 31, 2026
578721c
oxlint & validate_schema is shared
JulienChampagnol Jul 31, 2026
ad16646
Merge branch 'feat/app_controller' of https://github.com/Geode-soluti…
JulienChampagnol Jul 31, 2026
147952e
oxlint
JulienChampagnol Jul 31, 2026
d9550da
Apply prepare changes
JulienChampagnol Jul 31, 2026
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
102 changes: 26 additions & 76 deletions app/components/ObjectSelector.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup>
import FetchingData from "@ogw_front/components/FetchingData.vue";
import { geode_objects } from "@ogw_front/assets/geode_objects";
import { resolveAllowedObjects } from "@ogw_shared/utils/response_handlers/load.js.js";
import schemas from "@geode/opengeodeweb-back/opengeodeweb_back_schemas.json";
import { useBackStore } from "@ogw_front/stores/back";

Expand All @@ -15,100 +16,49 @@ const { filenames } = defineProps({
const backStore = useBackStore();

const loading = ref(false);
const allowed_objects = ref({});
const toggle_loading = useToggle(loading);
const multiple_files_no_common = ref(false);
const allowedGeodeObjects = ref({});
const toggleLoading = useToggle(loading);
const multipleFilesNoCommon = ref(false);

function select_geode_object(object_map) {
const object_keys = Object.keys(object_map);
if (object_keys.length === 0) {
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;
}

function isCsvFile(filename) {
return filename.toLowerCase().endsWith(".csv") || filename.toLowerCase().endsWith(".csv.json");
}

async function get_allowed_objects() {
toggle_loading();
allowed_objects.value = {};
multiple_files_no_common.value = false;

const promise_array = filenames.map((filename) => {
async function fetchAllowedObjectsList() {
const promiseArray = filenames.map((filename) => {
const params = { filename };
return backStore.request({ schema, params });
});
const responses = await Promise.all(promise_array);
const allowed_objects_list = responses.map((response) => response.allowed_objects);
const all_keys = [...new Set(allowed_objects_list.flatMap((obj) => Object.keys(obj)))];
const common_keys = all_keys.filter((key) => allowed_objects_list.every((obj) => key in obj));
const responses = await Promise.all(promiseArray);
return responses.map((response) => response.allowed_objects);
}

if (filenames.length > 1 && all_keys.length > 0 && common_keys.length === 0) {
multiple_files_no_common.value = true;
}
async function getAllowedGeodeObjects() {
toggleLoading();
allowedGeodeObjects.value = {};
multipleFilesNoCommon.value = false;

const final_object = {};
for (const key of common_keys) {
const load_scores = allowed_objects_list.map((obj) => obj[key].is_loadable);
const priorities = allowed_objects_list
.map((obj) => obj[key].object_priority)
.filter((priority) => priority !== undefined);
final_object[key] = { is_loadable: Math.min(...load_scores) };
if (priorities.length > 0) {
final_object[key].object_priority = Math.max(...priorities);
}
}
const isCsv = filenames.some((filename) => isCsvFile(filename));
if (isCsv && !final_object["PointSet3D"]) {
final_object["PointSet3D"] = { is_loadable: 1, object_priority: 100 };
}
const allowedGeodeObjectsList = await fetchAllowedObjectsList();
const resolved = resolveAllowedObjects(filenames, allowedGeodeObjectsList);

allowed_objects.value = final_object;
const selected_object = select_geode_object(final_object);
if (selected_object) {
set_geode_object(selected_object);
allowedGeodeObjects.value = resolved.allowedGeodeObjects;
multipleFilesNoCommon.value = resolved.multipleFilesNoCommon;
if (resolved.selectedGeodeObject) {
setGeodeObject(resolved.selectedGeodeObject);
}
toggle_loading();
toggleLoading();
}

function set_geode_object(geode_object_type) {
function setGeodeObject(geode_object_type) {
if (geode_object_type) {
emit("update_values", { geode_object_type });
emit("increment_step");
}
}
// oxlint-disable-next-line no-top-level-await
await get_allowed_objects();
await getAllowedGeodeObjects();
</script>

<template>
<FetchingData v-if="loading" />
<v-row v-else-if="Object.keys(allowed_objects).length" class="justify-left">
<v-col v-for="(value, key) in allowed_objects" :key="key" cols="3" md="4">
<v-row v-else-if="Object.keys(allowedGeodeObjects).length" class="justify-left">
<v-col v-for="(value, key) in allowedGeodeObjects" :key="key" cols="3" md="4">
<v-tooltip
:text="
value['is_loadable']
Expand All @@ -124,7 +74,7 @@ await get_allowed_objects();
class="card ma-2"
hover
rounded
@click="set_geode_object(key)"
@click="setGeodeObject(key)"
:disabled="!value['is_loadable']"
:elevation="value['is_loadable'] ? 5 : 3"
>
Expand All @@ -139,7 +89,7 @@ await get_allowed_objects();
</v-tooltip>
</v-col>
</v-row>
<v-row v-else-if="multiple_files_no_common" class="pa-5">
<v-row v-else-if="multipleFilesNoCommon" class="pa-5">
<v-card class="card" variant="tonal" rounded>
<v-card-text>
These files cannot be loaded together because they don't share a common data type.
Expand Down
29 changes: 22 additions & 7 deletions app/stores/app.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Local imports
import { getRestApiPort, getRestApiProtocol, isCloudMode } from "@ogw_front/utils/stores.js";
import { api_fetch } from "@ogw_internal/utils/api_fetch.js";
import { upload_file } from "@ogw_internal/utils/upload_file.js";

Expand All @@ -8,6 +9,20 @@ import { useInfraStore } from "@ogw_front/stores/infra";
// oxlint-disable-next-line max-lines-per-function, max-statements
export const useAppStore = defineStore("app", () => {
const stores = [];
const default_local_port = ref("3000");

const protocol = computed(() => getRestApiProtocol());

const port = computed(() => getRestApiPort(default_local_port.value));

const base_url = computed(() => {
const infraStore = useInfraStore();
let app_url = `${protocol.value}://${infraStore.domain_name}:${port.value}`;
if (isCloudMode()) {
app_url += `/server`;
}
return app_url;
});

function registerStore(store) {
const isAlreadyRegistered = stores.some((registeredStore) => registeredStore.$id === store.$id);
Expand Down Expand Up @@ -91,7 +106,7 @@ export const useAppStore = defineStore("app", () => {
return loadedExtensions.value.get(id);
}

async function loadExtension(path, port, backendPath = undefined) {
async function loadExtension(path, extensionPort, backendPath = undefined) {
try {
let finalURL = path;

Expand All @@ -108,7 +123,7 @@ export const useAppStore = defineStore("app", () => {
// oxlint-disable-next-line no-inline-comments
const extensionModule = await import(/* @vite-ignore */ finalURL);
const store = extensionModule.metadata.store();
store.$patch({ default_local_port: port });
store.$patch({ default_local_port: extensionPort });

if (finalURL !== path && finalURL.startsWith("blob:")) {
URL.revokeObjectURL(finalURL);
Expand Down Expand Up @@ -200,7 +215,7 @@ export const useAppStore = defineStore("app", () => {
const store = useAppStore();
return upload_file(
store,
{ route, file },
{ schema, file },
{
...callbacks,
response_function: async (response) => {
Expand All @@ -214,16 +229,13 @@ export const useAppStore = defineStore("app", () => {
}

function request({ schema, params }, callbacks = {}) {
console.log("[APP] Request:", schema.$id);

const store = useAppStore();
return api_fetch(
store,
{ schema, params, headers: {} },
{ schema, params },
{
...callbacks,
response_function: async (response) => {
console.log("[APP] Request completed:", schema.$id);
if (callbacks.response_function) {
await callbacks.response_function(response);
}
Expand All @@ -239,6 +251,7 @@ export const useAppStore = defineStore("app", () => {
function stop_request() {
request_counter.value -= 1;
}
const is_busy = computed(() => request_counter.value > 0);

const projectFolderPath = ref("");
function createProjectFolder() {
Expand All @@ -265,6 +278,7 @@ export const useAppStore = defineStore("app", () => {

return {
stores,
base_url,
registerStore,
exportStores,
importStores,
Expand All @@ -285,5 +299,6 @@ export const useAppStore = defineStore("app", () => {
createProjectFolder,
start_request,
stop_request,
is_busy,
};
});
36 changes: 10 additions & 26 deletions app/stores/back.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Status } from "@ogw_front/utils/status";
import { api_fetch } from "@ogw_internal/utils/api_fetch";
import { appMode } from "@ogw_front/utils/local/app_mode";
import back_schemas from "@geode/opengeodeweb-back/opengeodeweb_back_schemas.json";
import { upload_file } from "@ogw_internal/utils/upload_file.js";
import { useAppStore } from "@ogw_front/stores/app";
import { useFeedbackStore } from "@ogw_front/stores/feedback";
import { useInfraStore } from "@ogw_front/stores/infra";

import { getRestApiPort, getRestApiProtocol, isCloudMode } from "@ogw_front/utils/stores";

const MILLISECONDS_IN_SECOND = 1000;
const DEFAULT_PING_INTERVAL_SECONDS = 10;

Expand All @@ -19,24 +20,18 @@ export const useBackStore = defineStore("back", {
}),
getters: {
protocol() {
if (useInfraStore().app_mode === appMode.CLOUD) {
return "https";
}
return "http";
return getRestApiProtocol();
},
port() {
if (useInfraStore().app_mode === appMode.CLOUD) {
return "443";
}
return this.default_local_port;
return getRestApiPort(this.default_local_port);
},
base_url() {
const infraStore = useInfraStore();
let geode_url = `${this.protocol}://${infraStore.domain_name}:${this.port}`;
if (infraStore.app_mode === appMode.CLOUD) {
geode_url += `/geode`;
let back_url = `${this.protocol}://${infraStore.domain_name}:${this.port}`;
if (isCloudMode()) {
back_url += `/geode`;
}
return geode_url;
return back_url;
},
is_busy() {
return this.request_counter > 0;
Expand Down Expand Up @@ -110,22 +105,12 @@ export const useBackStore = defineStore("back", {
return Promise.resolve();
},
request({ schema, params = {} }, callbacks = {}) {
console.log("[GEODE] Request:", schema.$id);
const start = Date.now();

return api_fetch(
this,
{ schema, params, headers: {} },
{
...callbacks,
response_function: async (response) => {
console.log(
"[GEODE] Request completed:",
schema.$id,
"in",
(Date.now() - start) / MILLISECONDS_IN_SECOND,
"s",
);
if (callbacks.response_function) {
await callbacks.response_function(response);
}
Expand All @@ -134,17 +119,16 @@ export const useBackStore = defineStore("back", {
);
},
upload(file, callbacks = {}) {
const route = back_schemas.opengeodeweb_back.upload_file.$id;
const schema = back_schemas.opengeodeweb_back.upload_file;
return upload_file(
this,
{
route,
schema,
file,
},
{
...callbacks,
response_function: async (response) => {
console.log("[GEODE] Request completed:", route);
if (callbacks.response_function) {
await callbacks.response_function(response);
}
Expand Down
5 changes: 0 additions & 5 deletions app/stores/infra.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,6 @@ export const useInfraStore = defineStore("infra", {
},
async create_connection() {
console.log("[INFRA] Starting create_connection");
console.log(
"[INFRA] Connecting microservices:",
this.microservices.map((store) => store.$id),
);

await Promise.all(
this.microservices.map(async (store) => {
console.log("[INFRA] Connecting to microservice:", store.$id);
Expand Down
Loading
Loading