diff --git a/.github/workflows/deploy-test.yml b/.github/workflows/deploy-test.yml index 270c150..a1ec405 100644 --- a/.github/workflows/deploy-test.yml +++ b/.github/workflows/deploy-test.yml @@ -6,12 +6,17 @@ on: - main - 'feature/**' workflow_dispatch: + inputs: + branch: + description: "Branch to deploy" + required: true + default: main jobs: deploy: runs-on: ubuntu-latest env: - BRANCH_NAME: ${{ github.ref_name }} + BRANCH_NAME: ${{ github.event.inputs.branch || github.head_ref || github.ref_name }} steps: - name: Set up SSH agent @@ -26,8 +31,8 @@ jobs: - name: Deploy ${{ env.BRANCH_NAME }} to test server run: | - echo "➡️ Starting remote deployment of branch '${BRANCH_NAME}'" + echo "➡️ Starting remote deployment of branch $BRANCH_NAME" ssh -o StrictHostKeyChecking=no \ ${{ secrets.TEST_SERVER_USER }}@${{ secrets.TEST_SERVER_HOST }} \ - "bash ~/deploy_recapp_to_test.sh \"${BRANCH_NAME}\"" - echo "✅ Remote deployment of branch '${BRANCH_NAME}' succeeded" + "export BRANCH_NAME='${BRANCH_NAME}'; bash ~/deploy_recapp_to_test.sh '${BRANCH_NAME}'" + echo "✅ Remote deployment of branch $BRANCH_NAME succeeded" diff --git a/NEWS.md b/NEWS.md index 4fe1125..1a86eb2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,2 +1,2 @@ -# recapp 1.6.2 +# recapp 1.6.3 diff --git a/packages/backend/package.json b/packages/backend/package.json index 71182c2..b1c3403 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -48,5 +48,5 @@ "start": "ts-node ./src/index.ts", "test": "npm test" }, - "version": "1.0.0" + "version": "1.0.1" } diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 844d8fb..ee10955 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -1,7 +1,7 @@ { "name": "@recapp/frontend", "private": true, - "version": "1.6.2", + "version": "1.6.3", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/frontend/src/components/navigation/Root.tsx b/packages/frontend/src/components/navigation/Root.tsx index 9bca1ce..234ac56 100644 --- a/packages/frontend/src/components/navigation/Root.tsx +++ b/packages/frontend/src/components/navigation/Root.tsx @@ -2,17 +2,18 @@ import React, { useEffect, useState } from "react"; import { Outlet, useNavigate } from "react-router-dom"; -import { i18n } from "@lingui/core"; // keep if you use programmatic i18n APIs -import { Trans } from "@lingui/react"; // keep if you’re using anywhere +import { i18n } from "@lingui/core"; +import { Trans } from "@lingui/react"; import { Layout } from "../../layout/Layout"; import { SystemContext } from "ts-actors-react"; -import { Button, Modal } from "react-bootstrap"; +import { Button, Modal, Spinner } from "react-bootstrap"; import { cookie } from "../../utils"; import { system } from "../../system"; import { ActorSystem } from "ts-actors"; import { Try, fromError, fromValue } from "tsmonads"; export const Root: React.FC = () => { + // 1) Keep the monadic Try so it matches your context type const [init, setInit] = useState>(fromError(new Error())); const [rpcError, setRpcError] = useState(""); const navigate = useNavigate(); @@ -22,57 +23,80 @@ export const Root: React.FC = () => { document.location.href = `${import.meta.env.VITE_BACKEND_URI}/auth/logout`; }; - // 1) Initialize the actor system once on mount + // 2) Bootstrap the actor system just once useEffect(() => { - const run = async () => { - try { - const s: ActorSystem = await system; - setInit(fromValue(s)); - } catch (e) { - setInit(fromError(e as Error)); - } - }; - run(); + system + .then(s => setInit(fromValue(s))) + .catch(err => setInit(fromError(err))); }, []); - // 2) After initialization, check the bearer cookie and redirect if missing + // 3) After a successful init, check for the bearer cookie and redirect if missing useEffect(() => { - if (init.isValue) { - if (!cookie("bearer")) { - navigate("/", { replace: true }); + init.match( + // onSuccess + () => { + if (!cookie("bearer")) { + navigate("/", { replace: true }); + } + }, + // onFailure + () => { + /* do nothing on failure; modal handle below */ } - } + ); }, [init, navigate]); - // 3) Handle any RPC‐level errors in a modal - if (rpcError !== "") { + // 4) If we hit an RPC error, show the modal + if (rpcError) { return ( setRpcError("")}> - Communication Error + + + - There was a problem communicating with the backend. +
- Please try again or contact support. +
); } - // 4) While the actor system is initializing, render nothing (or a spinner) - if (!init.isValue) { - return null; + // 5) While initializing, show a centered spinner + const ready = init.match(() => true, () => false); + if (!ready) { + return ( +
+ + + + + +
+ ); } - // 5) Once ready and authenticated, render the layout and child routes + // 6) Everything’s good: render your app return ( - +