From 0b9bfa5a50fb8b508264dfd3f03204a4974f8d96 Mon Sep 17 00:00:00 2001 From: spaenleh Date: Mon, 16 Feb 2026 10:59:28 +0100 Subject: [PATCH 1/8] fix: make changes necessary for single origin --- .dockerignore | 1 + src/config/i18n.ts | 2 +- vite.config.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index ea90c5605..30151a930 100644 --- a/.dockerignore +++ b/.dockerignore @@ -11,3 +11,4 @@ Dockerfile docs node_modules storybook_static +.tanstack diff --git a/src/config/i18n.ts b/src/config/i18n.ts index c1c2a4581..9f836f550 100644 --- a/src/config/i18n.ts +++ b/src/config/i18n.ts @@ -14,7 +14,7 @@ i18n // namespaces that will be loaded by default ns: ['common'], backend: { - loadPath: '/locales/{{lng}}/{{ns}}.json', + loadPath: `${import.meta.env.PROD ? '/client' : ''}/locales/{{lng}}/{{ns}}.json`, }, // specify which languages are supported // 1. prefers exact match across all supported langs diff --git a/vite.config.ts b/vite.config.ts index 30e41077f..e5d0100df 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -33,7 +33,7 @@ const config = ({ mode }: { mode: string }): UserConfig => { const shouldOpen = BROWSER && BROWSER !== 'none'; return defineConfig({ - base: '/', + base: process.env.NODE_ENV == 'production' ? '/client' : '/', server: { port: PORT, // whether we should open the url on start From e9914e30f657aa001beb6df2fca8b61a7554ac88 Mon Sep 17 00:00:00 2001 From: spaenleh Date: Tue, 24 Feb 2026 15:43:21 +0100 Subject: [PATCH 2/8] fix: tests --- .github/workflows/deploy.yml | 1 - src/config/env.ts | 7 +++++-- src/config/i18n.ts | 4 +++- src/config/queryClient.ts | 14 ++++++-------- vite.config.ts | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5970636c8..8042da8bc 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -47,7 +47,6 @@ jobs: env: VITE_VERSION: ${{ inputs.version || github.sha }} VITE_GRAASP_API_HOST: ${{ vars.VITE_GRAASP_API_HOST }} - VITE_GRAASP_WS_HOST: ${{ vars.VITE_GRAASP_WS_HOST }} VITE_GRAASP_LIBRARY_HOST: ${{ vars.VITE_GRAASP_LIBRARY_HOST }} VITE_SENTRY_ENV: ${{ vars.VITE_SENTRY_ENV }} VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }} diff --git a/src/config/env.ts b/src/config/env.ts index c52021917..bd2bc6c4d 100644 --- a/src/config/env.ts +++ b/src/config/env.ts @@ -1,8 +1,7 @@ export const API_HOST = import.meta.env.VITE_GRAASP_API_HOST ?? 'http://localhost:3000'; -export const WS_HOST = - import.meta.env.VITE_GRAASP_WS_HOST ?? 'ws://localhost:3000'; +export const WS_HOST = API_HOST.replace('http', 'ws'); export const SHOW_NOTIFICATIONS = (import.meta.env.VITE_SHOW_NOTIFICATIONS ?? 'true') === 'true'; @@ -31,3 +30,7 @@ export const H5P_INTEGRATION_URL = // Question: should we host the pdf player assets inside the public directory here instead of at another bucket ? // Are there any security implications if it is hosted on the same domain as the app code ? export const GRAASP_ASSETS_URL = import.meta.env.VITE_GRAASP_ASSETS_URL; + +export const BASE_FOR_LOCALE = import.meta.env.VITE_BASE_LOCALE + ? '/client' + : ''; diff --git a/src/config/i18n.ts b/src/config/i18n.ts index 9f836f550..ff8511eb9 100644 --- a/src/config/i18n.ts +++ b/src/config/i18n.ts @@ -14,7 +14,9 @@ i18n // namespaces that will be loaded by default ns: ['common'], backend: { - loadPath: `${import.meta.env.PROD ? '/client' : ''}/locales/{{lng}}/{{ns}}.json`, + loadPath: `${ + import.meta.env.VITE_BASE_URL ? '/client' : '' + }/locales/{{lng}}/{{ns}}.json`, }, // specify which languages are supported // 1. prefers exact match across all supported langs diff --git a/src/config/queryClient.ts b/src/config/queryClient.ts index c029c0e0a..1f5b228b3 100644 --- a/src/config/queryClient.ts +++ b/src/config/queryClient.ts @@ -2,12 +2,10 @@ import { configureWebsocketClient } from '@graasp/sdk'; import { configureQueryClient } from '@/query'; -import { API_HOST, SHOW_NOTIFICATIONS } from './env'; +import { API_HOST, SHOW_NOTIFICATIONS, WS_HOST } from './env'; import notifier from './notifier'; -export const WS_CLIENT = configureWebsocketClient( - `${API_HOST.replace('http', 'ws')}/ws`, -); +export const WS_CLIENT = configureWebsocketClient(WS_HOST); const { queryClient, @@ -29,13 +27,13 @@ const { wsClient: WS_CLIENT, }); export { - useQueryClient, + axios, + hooks, mutations, queryClient, QueryClientProvider, - hooks, - useMutation, ReactQueryDevtools, - axios, + useMutation, useQuery, + useQueryClient, }; diff --git a/vite.config.ts b/vite.config.ts index e5d0100df..68b5a3076 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -33,7 +33,7 @@ const config = ({ mode }: { mode: string }): UserConfig => { const shouldOpen = BROWSER && BROWSER !== 'none'; return defineConfig({ - base: process.env.NODE_ENV == 'production' ? '/client' : '/', + base: process.env.VITE_BASE_URL ? '/client' : '/', server: { port: PORT, // whether we should open the url on start From da40c6e9237572fd2193d5944bed11f832c078fe Mon Sep 17 00:00:00 2001 From: spaenleh Date: Tue, 24 Feb 2026 16:50:56 +0100 Subject: [PATCH 3/8] fix: tests --- cypress/e2e/builder/item/bookmarks/bookmarks.cy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/builder/item/bookmarks/bookmarks.cy.ts b/cypress/e2e/builder/item/bookmarks/bookmarks.cy.ts index 99ea860ab..86c6dd849 100644 --- a/cypress/e2e/builder/item/bookmarks/bookmarks.cy.ts +++ b/cypress/e2e/builder/item/bookmarks/bookmarks.cy.ts @@ -26,7 +26,7 @@ const removefromItemCard = (itemId: string) => { cy.get(`#${buildItemCard(itemId)} ${UNBOOKMARK_ICON_SELECTOR}`).click(); }; const removefromBookmarkCard = (itemId: string) => { - cy.get(`#${BOOKMARK_MANAGE_BUTTON_ID} `).click(); + cy.get(`#${BOOKMARK_MANAGE_BUTTON_ID}`).click(); cy.get(buildBookmarkCardRemoveButton(itemId)).click(); }; @@ -85,7 +85,7 @@ describe('Bookmarked Item', () => { }); }); - it('remove item from item card', () => { + it('remove item from bookmark card', () => { const itemId = ITEMS[1].id; removefromBookmarkCard(itemId); From 10d2d030131cddddff315a3543e43fd241522c21 Mon Sep 17 00:00:00 2001 From: spaenleh Date: Wed, 25 Feb 2026 08:15:12 +0100 Subject: [PATCH 4/8] fix: update test mocks --- cypress/support/commands.ts | 3 +++ cypress/support/server.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 99c6443cd..367ac81f0 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -142,6 +142,7 @@ import { mockPostAvatar, mockPostInvitations, mockPostItem, + mockPostItemActions, mockPostItemChatMessage, mockPostItemFlag, mockPostItemLogin, @@ -541,6 +542,8 @@ Cypress.Commands.add( mockEnroll(); mockGetCurrentSettings(currentMember, currentSettings); + + mockPostItemActions(); }, ); diff --git a/cypress/support/server.ts b/cypress/support/server.ts index d42e4f8b6..5cb2ca849 100644 --- a/cypress/support/server.ts +++ b/cypress/support/server.ts @@ -998,6 +998,22 @@ export const mockGetItemChat = ( { items }: { items: ItemForTest[] }, shouldThrowError: boolean, ): void => { + cy.intercept( + { + method: HttpMethod.Get, + pathname: /\/api\/items\/[0-9a-fA-F-]{36}\/chat$/, + }, + ({ reply, url }) => { + if (shouldThrowError) { + return reply({ statusCode: StatusCodes.BAD_REQUEST }); + } + + const itemId = url.split('/')[-2]; + const item = items.find(({ id }) => itemId === id); + + return reply(item?.chat ?? []); + }, + ).as('getItemChatAPI'); cy.intercept( { method: HttpMethod.Get, @@ -2424,3 +2440,15 @@ export const mockGetCurrentSettings = ( }, ).as('getCurrentSettings'); }; + +export const mockPostItemActions = (): void => { + cy.intercept( + { + method: HttpMethod.Post, + pathname: /\/api\/items\/[0-9a-fA-F-]{36}\/actions$/, + }, + ({ reply }) => { + reply([]); + }, + ).as('postItemActions'); +}; From d91a49e4172b6ef7a02be1f2c8215affb1652d96 Mon Sep 17 00:00:00 2001 From: spaenleh Date: Wed, 25 Feb 2026 08:56:57 +0100 Subject: [PATCH 5/8] fix: reply with empty object to fix promise rejection issue --- cypress/e2e/account/settings/preferences.cy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/account/settings/preferences.cy.ts b/cypress/e2e/account/settings/preferences.cy.ts index 03e480894..ddab89c66 100644 --- a/cypress/e2e/account/settings/preferences.cy.ts +++ b/cypress/e2e/account/settings/preferences.cy.ts @@ -70,7 +70,7 @@ describe('Display preferences', () => { } }); - describe('Marketing emails subscription', () => { + describe.only('Marketing emails subscription', () => { it('Enabled', () => { cy.setUpApi({ currentSettings: { @@ -83,7 +83,7 @@ describe('Display preferences', () => { pathname: /\/api\/members\/current\/marketing\/unsubscribe$/, }, ({ reply }) => { - reply(); + reply({}); }, ).as('unsubscribe'); From c0dbce87c754ce32c585fe595f3049ac0e5530fe Mon Sep 17 00:00:00 2001 From: spaenleh Date: Wed, 25 Feb 2026 09:16:55 +0100 Subject: [PATCH 6/8] chore: update timeout of unit test workflow --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ec670a8ec..01f183971 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: unit: name: Unit runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 steps: - name: Checkout uses: actions/checkout@v4 From 771c80401efc9dfb408073df69d3ef743412b512 Mon Sep 17 00:00:00 2001 From: spaenleh Date: Wed, 25 Feb 2026 09:18:35 +0100 Subject: [PATCH 7/8] fix: remove only --- cypress/e2e/account/settings/preferences.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/account/settings/preferences.cy.ts b/cypress/e2e/account/settings/preferences.cy.ts index ddab89c66..c20b712a2 100644 --- a/cypress/e2e/account/settings/preferences.cy.ts +++ b/cypress/e2e/account/settings/preferences.cy.ts @@ -70,7 +70,7 @@ describe('Display preferences', () => { } }); - describe.only('Marketing emails subscription', () => { + describe('Marketing emails subscription', () => { it('Enabled', () => { cy.setUpApi({ currentSettings: { From e4f4661666c5cd2d579e4105fd01e762afd6486c Mon Sep 17 00:00:00 2001 From: spaenleh Date: Wed, 25 Feb 2026 09:20:51 +0100 Subject: [PATCH 8/8] fix: remove unused env var --- src/config/env.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/config/env.ts b/src/config/env.ts index bd2bc6c4d..573186f8a 100644 --- a/src/config/env.ts +++ b/src/config/env.ts @@ -30,7 +30,3 @@ export const H5P_INTEGRATION_URL = // Question: should we host the pdf player assets inside the public directory here instead of at another bucket ? // Are there any security implications if it is hosted on the same domain as the app code ? export const GRAASP_ASSETS_URL = import.meta.env.VITE_GRAASP_ASSETS_URL; - -export const BASE_FOR_LOCALE = import.meta.env.VITE_BASE_LOCALE - ? '/client' - : '';