Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b123a2d
adding app-store.js to save all stores and loop all keys and return t…
MaxNumerique Oct 10, 2025
e333824
Apply prepare changes
MaxNumerique Oct 13, 2025
0bd7e41
app_store can now get stores automatically and returns getters
MaxNumerique Oct 13, 2025
71a8d10
app_store corrected, local test update
MaxNumerique Oct 13, 2025
38cad80
tests for app_store integration with 2 mocked stores
MaxNumerique Oct 13, 2025
0eabae1
feat(app_store): Store that register all stores to save all keys from…
MaxNumerique Oct 13, 2025
a6a5774
added setup mode for tests
MaxNumerique Oct 13, 2025
14590f9
mixed stores in register() and save&load()
MaxNumerique Oct 13, 2025
dadfcb3
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 13, 2025
89eba03
adding tracking options with storeId, action, params, timestamp
MaxNumerique Oct 13, 2025
39edaab
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 13, 2025
c79e889
Apply prepare changes
MaxNumerique Oct 13, 2025
9050cef
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 14, 2025
8020882
Merge branch 'feat/app_store' of https://github.com/Geode-solutions/O…
MaxNumerique Oct 14, 2025
5059428
save and load from selected store
MaxNumerique Oct 14, 2025
5276aaa
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 16, 2025
fe621e4
adapts test
MaxNumerique Oct 16, 2025
a27cb46
add getActivePinia
MaxNumerique Oct 16, 2025
283b38c
app_store
MaxNumerique Oct 16, 2025
2ab91d8
setup mode
MaxNumerique Oct 16, 2025
488e0e0
re arragne return
MaxNumerique Oct 16, 2025
90c181c
tests with mocked stores
MaxNumerique Oct 16, 2025
1f1074c
reduced scope
MaxNumerique Oct 16, 2025
7502e85
log
MaxNumerique Oct 16, 2025
de256df
forcing import of app_store and security verification
MaxNumerique Oct 16, 2025
e59fed1
update plugin autoStoreRegister
MaxNumerique Oct 17, 2025
3ae074c
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 17, 2025
169811a
Apply prepare changes
MaxNumerique Oct 17, 2025
1ece0a7
removed unecessary verification
MaxNumerique Oct 17, 2025
11fccf8
Merge branch 'feat/app_store' of https://github.com/Geode-solutions/O…
MaxNumerique Oct 17, 2025
08d247e
Apply prepare changes
MaxNumerique Oct 17, 2025
e28a1af
test
MaxNumerique Oct 17, 2025
b593b8c
Merge branch 'feat/app_store' of https://github.com/Geode-solutions/O…
MaxNumerique Oct 17, 2025
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
29 changes: 29 additions & 0 deletions plugins/autoStoreRegister.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useAppStore } from "../stores/app_store"

export const autoStoreRegister = ({ store }) => {
if (!store || !store.$id) {
console.warn("[AutoRegister] Invalid store object received", store)
return
}

if (store.$id === "app") {
return
}

const appStore = useAppStore()

const isAlreadyRegistered = appStore.stores.some(
(registeredStore) => registeredStore.$id === store.$id,
)

if (!isAlreadyRegistered) {
appStore.registerStore(store)
console.log(`[AutoRegister] Store "${store.$id}" registered`)
} else {
console.log(
`[AutoRegister] Store "${store.$id}" already registered, skipping`,
)
}
}

export default autoStoreRegister
74 changes: 74 additions & 0 deletions stores/app_store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
export const useAppStore = defineStore("app", () => {
const stores = []

function registerStore(store) {
console.log("[AppStore] Registering store", store.$id)
stores.push(store)
}

function save() {
const snapshot = {}
let savedCount = 0

for (const store of stores) {
if (!store.save) {
continue
}
const storeId = store.$id
try {
snapshot[storeId] = store.save()
savedCount++
} catch (error) {
console.error(`[AppStore] Error saving store "${storeId}":`, error)
}
}

console.log(`[AppStore] Saved ${savedCount} stores`)
return snapshot
}

function load(snapshot) {
if (!snapshot) {
console.warn("[AppStore] load called with invalid snapshot")
return
}

let loadedCount = 0
const notFoundStores = []

for (const store of stores) {
if (!store.load) {
continue
}

const storeId = store.$id

if (!snapshot[storeId]) {
notFoundStores.push(storeId)
continue
}

try {
store.load(snapshot[storeId])
loadedCount++
} catch (error) {
console.error(`[AppStore] Error loading store "${storeId}":`, error)
}
}

if (notFoundStores.length > 0) {
console.warn(
`[AppStore] Stores not found in snapshot: ${notFoundStores.join(", ")}`,
)
}

console.log(`[AppStore] Loaded ${loadedCount} stores`)
}

return {
stores,
registerStore,
save,
load,
}
})
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==5.*,>=5.10.3
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.11.3
206 changes: 206 additions & 0 deletions tests/unit/stores/Appstore.nuxt.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { beforeEach, describe, expect, expectTypeOf, test, vi } from "vitest"
import { createTestingPinia } from "@pinia/testing"
import { useAppStore } from "@/stores/app_store.js"
import { setActivePinia } from "pinia"

beforeEach(async () => {
const pinia = createTestingPinia({
stubActions: false,
createSpy: vi.fn,
})
setActivePinia(pinia)
})

describe("App Store", () => {
describe("state", () => {
test("initial state", () => {
const app_store = useAppStore()
expectTypeOf(app_store.stores).toBeArray()
expectTypeOf(app_store.save).toBeFunction()
expectTypeOf(app_store.load).toBeFunction()
expectTypeOf(app_store.registerStore).toBeFunction()
})
})

describe("actions", () => {
describe("registerStore", () => {
test("register single store", () => {
const app_store = useAppStore()
const mock_store = {
$id: "testStore",
save: vi.fn().mockImplementation(() => ({ data: "test" })),
load: vi.fn().mockImplementation(() => {}),
}

app_store.registerStore(mock_store)

expect(app_store.stores.length).toBe(1)
expect(app_store.stores[0]).toStrictEqual(mock_store)
})

test("register multiple stores", () => {
const app_store = useAppStore()
const mock_store_1 = {
$id: "userStore",
save: vi.fn().mockImplementation(() => {}),
load: vi.fn().mockImplementation(() => {}),
}
const mock_store_2 = {
$id: "cartStore",
save: vi.fn().mockImplementation(() => {}),
load: vi.fn().mockImplementation(() => {}),
}

app_store.registerStore(mock_store_1)
app_store.registerStore(mock_store_2)

expect(app_store.stores.length).toBe(2)
expect(app_store.stores[0].$id).toBe("userStore")
expect(app_store.stores[1].$id).toBe("cartStore")
})
})

describe("save", () => {
test("save stores with save method", () => {
const app_store = useAppStore()
const mock_store_1 = {
$id: "userStore",
save: vi.fn().mockImplementation(() => ({
name: "toto",
email: "[email protected]",
})),
load: vi.fn().mockImplementation(() => {}),
}
const mock_store_2 = {
$id: "cartStore",
save: vi.fn().mockImplementation(() => ({ items: [], total: 0 })),
load: vi.fn().mockImplementation(() => {}),
}

app_store.registerStore(mock_store_1)
app_store.registerStore(mock_store_2)

const snapshot = app_store.save()

expect(mock_store_1.save).toHaveBeenCalledTimes(1)
expect(mock_store_2.save).toHaveBeenCalledTimes(1)
expect(snapshot).toEqual({
userStore: { name: "toto", email: "[email protected]" },
cartStore: { items: [], total: 0 },
})
})

test("skip stores without save method", () => {
const app_store = useAppStore()
const mock_store_1 = {
$id: "withSave",
save: vi.fn().mockImplementation(() => ({ data: "test" })),
load: vi.fn().mockImplementation(() => {}),
}
const mock_store_2 = {
$id: "withoutSave",
load: vi.fn().mockImplementation(() => {}),
}

app_store.registerStore(mock_store_1)
app_store.registerStore(mock_store_2)

const snapshot = app_store.save()

expect(mock_store_1.save).toHaveBeenCalledTimes(1)
expect(snapshot).toEqual({
withSave: { data: "test" },
})
expect(snapshot.withoutSave).toBeUndefined()
})

test("return empty snapshot when no stores registered", () => {
const app_store = useAppStore()
const snapshot = app_store.save()
expect(snapshot).toEqual({})
})
})

describe("load", () => {
test("load stores with load method", () => {
const app_store = useAppStore()
const mock_store_1 = {
$id: "userStore",
save: vi.fn().mockImplementation(() => {}),
load: vi.fn().mockImplementation(() => {}),
}
const mock_store_2 = {
$id: "cartStore",
save: vi.fn().mockImplementation(() => {}),
load: vi.fn().mockImplementation(() => {}),
}

app_store.registerStore(mock_store_1)
app_store.registerStore(mock_store_2)

const snapshot = {
userStore: { name: "tata", email: "[email protected]" },
cartStore: { items: [{ id: 1 }], total: 50 },
}

app_store.load(snapshot)

expect(mock_store_1.load).toHaveBeenCalledTimes(1)
expect(mock_store_1.load).toHaveBeenCalledWith({
name: "tata",
email: "[email protected]",
})
expect(mock_store_2.load).toHaveBeenCalledTimes(1)
expect(mock_store_2.load).toHaveBeenCalledWith({
items: [{ id: 1 }],
total: 50,
})
})

test("skip stores without load method", () => {
const app_store = useAppStore()
const mock_store_1 = {
$id: "withLoad",
save: vi.fn().mockImplementation(() => {}),
load: vi.fn().mockImplementation(() => {}),
}
const mock_store_2 = {
$id: "withoutLoad",
save: vi.fn().mockImplementation(() => {}),
}

app_store.registerStore(mock_store_1)
app_store.registerStore(mock_store_2)

const snapshot = {
withLoad: { data: "test" },
withoutLoad: { data: "ignored" },
}

app_store.load(snapshot)

expect(mock_store_1.load).toHaveBeenCalledTimes(1)
expect(mock_store_2.load).toBeUndefined()
})

test("warn when store not found in snapshot", () => {
const app_store = useAppStore()
const console_warn_spy = vi
.spyOn(console, "warn")
.mockImplementation(() => {})
const mock_store = {
$id: "testStore",
load: vi.fn().mockImplementation(() => {}),
}

app_store.registerStore(mock_store)
app_store.load({})

expect(console_warn_spy).toHaveBeenCalledWith(
expect.stringContaining("Stores not found in snapshot: testStore"),
)
console_warn_spy.mockRestore()
})
})
})
})