diff --git a/Dockerfile b/Dockerfile index 3e060b74c..9f4eb510d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,6 +39,10 @@ COPY . /app ARG VITE_ASSET_SET=neutral ENV VITE_ASSET_SET=$VITE_ASSET_SET +# Set release tag so we can show our deployment version to users +ARG VITE_RELEASE_TAG=Developing +ENV VITE_RELEASE_TAG=$VITE_RELEASE_TAG + RUN npm install \ && chmod a+x /docker-entrypoint.sh \ && npm run build \ diff --git a/package-lock.json b/package-lock.json index 79076ec3f..9cbb75ff5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2658,9 +2658,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -4060,9 +4060,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", @@ -5511,9 +5511,9 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/vite": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.5.tgz", - "integrity": "sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==", + "version": "4.5.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.9.tgz", + "integrity": "sha512-qK9W4xjgD3gXbC0NmdNFFnVFLMWSNiR3swj957yutwzzN16xF/E7nmtAyp1rT9hviDroQANjE4HK3H4WqWdFtw==", "dev": true, "dependencies": { "esbuild": "^0.18.10", diff --git a/src/assets/icons/kclogo.svg b/src/assets/icons/kclogo.svg new file mode 100644 index 000000000..4806156c4 --- /dev/null +++ b/src/assets/icons/kclogo.svg @@ -0,0 +1 @@ + diff --git a/src/assets/locale/en.json b/src/assets/locale/en.json index 1bf834e76..d79aa19ef 100644 --- a/src/assets/locale/en.json +++ b/src/assets/locale/en.json @@ -162,6 +162,10 @@ "manageUsersView.addUsers": "Add Users", "manageUsersView.approveUsers": "Approve Users", "manageUsersView.manageUsers": "Manage Users", + "manageUsersView.keycloakAccess": "Access Keycloak (Beta)", + "manageUsersView.keycloakAccessDesc1": "Keycloak is a backend service, which syncs user's roles and groups across services integrated to Deploy App. Managing groups is not necessary right now.", + "manageUsersView.keycloakAccessDesc2": "If you know how to use it, you may access it from the button below. Later on, user role & group management will be done directly here in Deploy App for maximum ease of use.", + "manageUsersView.openKeycloak": "Open Keycloak", "USERMANAGEMENTVIEW": "USERMANAGEMENTVIEW", "userManagement.rejectionSuccessMessage": "Success: The user has been removed.", diff --git a/src/assets/locale/fi.json b/src/assets/locale/fi.json index e2f4c963e..1a8721b73 100644 --- a/src/assets/locale/fi.json +++ b/src/assets/locale/fi.json @@ -163,6 +163,10 @@ "manageUsersView.addUsers": "Lisää käyttäjiä", "manageUsersView.approveUsers": "Hyväksy käyttäjiä", "manageUsersView.manageUsers": "Hallitse käyttäjiä", + "manageUsersView.keycloakAccess": "Avaa Keycloak (Beta)", + "manageUsersView.keycloakAccessDesc1": "Keycloak on taustapalvelu, joka synkronoi käyttäjien roolit ja ryhmät Deploy App-palvelimessasi mukana olevien palveluiden välillä. Sen käyttäminen ei ole tällä hetkellä välttämätöntä.", + "manageUsersView.keycloakAccessDesc2": "Jos osaat käyttää Keycloakia, voit avata sen alla olevasta painikkeesta. Myöhemmin käyttäjien rooli- ja ryhmähallinta tehdään suoraan Deploy Appissa, jotta käyttökokemus olisi mahdollisimman helppo.", + "manageUsersView.openKeycloak": "Avaa Keycloak", "USERMANAGEMENTVIEW": "USERMANAGEMENTVIEW", "userManagement.rejectionSuccessMessage": "Käyttäjän hylkääminen onnistui.", diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 2e1bab02c..8904dd952 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -2,13 +2,15 @@ import { Trans, useTranslation } from "react-i18next"; import { InfoModal } from "./InfoModal"; import { DropdownMenu } from "./DropdownMenu"; import { useLanguageChange } from "./Localization/LanguageChange"; -import useHealthCheck from "../hook/helpers/useHealthcheck"; export function Footer() { - // Use both common and dynamic namespaces const { t } = useTranslation(["common", "dynamic"]); const isMtls = window.location.origin.includes("mtls."); - const { version } = useHealthCheck(); + + // Read the deployment version from VITE_RELEASE_TAG + const deploymentVersion = + (import.meta.env.VITE_RELEASE_TAG as string) || t("footer.loading"); + const feedbackLink = t("footer.feedbackForm", { ns: "dynamic" }); const { changeLanguage, availableLanguages } = useLanguageChange(); @@ -21,9 +23,8 @@ export function Footer() { return (
); diff --git a/src/views/login/EnrollmentView.tsx b/src/views/login/EnrollmentView.tsx index 0d68f7abe..871b9fffc 100644 --- a/src/views/login/EnrollmentView.tsx +++ b/src/views/login/EnrollmentView.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import QRCode from "react-qr-code"; import { useOwnEnrollmentStatus } from "../../hook/api/useOwnEnrollmentStatus"; import { useNavigate } from "react-router-dom"; @@ -16,30 +16,39 @@ export function EnrollmentView() { const { isCopied, copyError, handleCopy } = useCopyToClipboard(); const callsign = localStorage.getItem("callsign") ?? undefined; const approveCode = localStorage.getItem("approveCode") ?? undefined; + + // Build the approval URL. const protocol = window.location.protocol; const host = window.location.host; const approvalUrl = `${protocol}//mtls.${host}/app/admin/user-management/approval?callsign=${ callsign ?? "" }&&approvalcode=${approveCode ?? ""}`; - // Redirect to login if approveCode or callsign is missing + // Local state to control polling behavior + const [shouldPoll, setShouldPoll] = useState(true); + + // Redirect to login if approveCode or callsign is missing. useEffect(() => { if (!approveCode || !callsign) { navigate("/login"); } }, [approveCode, callsign, navigate]); - // Check enrollment status periodically and navigate on success - useOwnEnrollmentStatus({ - onSuccess: (enrolled) => { - if (enrolled) { - navigate("/login/createmtls"); - } - }, - refetchInterval: 1000, + // Use the enrollment status hook. + const { data: enrolled, isLoading } = useOwnEnrollmentStatus({ + refetchInterval: shouldPoll ? 5000 : false, // Stop polling once enrolled }); - // Render the waiting for approval view + // Effect to navigate on successful enrollment + useEffect(() => { + if (enrolled && shouldPoll) { + setShouldPoll(false); // Stop polling to prevent infinite re-renders + + // Use hard redirect to force React to unmount the view + window.location.replace("/login/createmtls"); + } + }, [enrolled, shouldPoll]); + return (