diff --git a/.github/workflows/deploy-images-on-release.yml b/.github/workflows/deploy-images-on-release.yml
index f1d0dd7ce..cf06f7840 100644
--- a/.github/workflows/deploy-images-on-release.yml
+++ b/.github/workflows/deploy-images-on-release.yml
@@ -11,6 +11,9 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
- name: Extract version from tag
id: extract_tag
run: echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
@@ -93,6 +96,8 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -119,12 +124,16 @@ jobs:
platforms: linux/amd64,linux/arm64
labels: |
org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate
+ build-args: |
+ VITE_APP_VERSION=${{ steps.extract_tag.outputs.version }}
docker-build-and-push-server-mono:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
- name: Extract version
id: extract_tag
@@ -143,6 +152,7 @@ jobs:
-t ghcr.io/bluewave-labs/checkmate-backend-mono:${{ steps.extract_tag.outputs.version }} \
-f ./docker/dist-mono/server.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
+ --build-arg VITE_APP_VERSION=${{ steps.extract_tag.outputs.version }} \
.
- name: Push Server Docker image
diff --git a/.github/workflows/deploy-images.yml b/.github/workflows/deploy-images.yml
index d3d70b90b..fa39fed85 100644
--- a/.github/workflows/deploy-images.yml
+++ b/.github/workflows/deploy-images.yml
@@ -10,6 +10,8 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
@@ -18,12 +20,16 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Get version
+ id: vars
+ run: echo "VERSION=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
- name: Build Client Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-client:latest \
-f ./docker/dist/client.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
+ --build-arg VITE_APP_VERSION=${{ env.VERSION }} \
.
- name: Push Client Docker image
@@ -85,6 +91,8 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -96,6 +104,10 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Get version
+ id: vars
+ run: echo "VERSION=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
+
- name: Build and push multi-arch Docker image
uses: docker/build-push-action@v5
with:
@@ -107,12 +119,16 @@ jobs:
platforms: linux/amd64,linux/arm64
labels: |
org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate
+ build-args: |
+ VITE_APP_VERSION=${{ env.VERSION }}
docker-build-and-push-server-mono:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
@@ -121,12 +137,17 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Get version
+ id: vars
+ run: echo "VERSION=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
+
- name: Build Server Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-backend-mono:latest \
-f ./docker/dist-mono/server.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
+ --build-arg VITE_APP_VERSION=${{ env.VERSION }} \
.
- name: Push Server Docker image
diff --git a/.github/workflows/production-deploy.yml b/.github/workflows/production-deploy.yml
index 6956f5caa..7764c488b 100644
--- a/.github/workflows/production-deploy.yml
+++ b/.github/workflows/production-deploy.yml
@@ -10,6 +10,8 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
@@ -18,12 +20,16 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Get version
+ id: vars
+ run: echo "VERSION=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
- name: Build Client Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate:frontend-demo \
-f ./docker/prod/client.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
+ --build-arg VITE_APP_VERSION=${{ env.VERSION }} \
.
- name: Push Client Docker image
diff --git a/.github/workflows/staging-deploy.yml b/.github/workflows/staging-deploy.yml
index 34fa243c6..ea5477815 100644
--- a/.github/workflows/staging-deploy.yml
+++ b/.github/workflows/staging-deploy.yml
@@ -10,6 +10,8 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
@@ -18,12 +20,16 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Get version
+ id: vars
+ run: echo "VERSION=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
- name: Build Client Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate:frontend-staging \
-f ./docker/staging/client.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
+ --build-arg VITE_APP_VERSION=${{ env.VERSION }} \
.
- name: Push Client Docker image
diff --git a/client/src/Components/RoleProtectedRoute/index.jsx b/client/src/Components/RoleProtectedRoute/index.jsx
new file mode 100644
index 000000000..c7b7dfc12
--- /dev/null
+++ b/client/src/Components/RoleProtectedRoute/index.jsx
@@ -0,0 +1,35 @@
+import { Navigate } from "react-router-dom";
+import { useSelector } from "react-redux";
+import PropTypes from "prop-types";
+
+/**
+ * ProtectedRoute is a wrapper component that ensures only authenticated users
+ * can access the wrapped content. It checks authentication status (e.g., from Redux or Context).
+ * If the user is authenticated, it renders the children; otherwise, it redirects to the login page.
+ *
+ * @param {Object} props - The props passed to the ProtectedRoute component.
+ * @param {React.ReactNode} props.children - The children to render if the user is authenticated.
+ * @returns {React.ReactElement} The children wrapped in a protected route or a redirect to the login page.
+ */
+
+const RoleProtectedRoute = ({ roles, children }) => {
+ const authState = useSelector((state) => state.auth);
+ const userRoles = authState?.user?.role || [];
+ const canAccess = userRoles.some((role) => roles.includes(role));
+
+ return canAccess ? (
+ children
+ ) : (
+
+ );
+};
+
+RoleProtectedRoute.propTypes = {
+ children: PropTypes.element.isRequired,
+ roles: PropTypes.array,
+};
+
+export default RoleProtectedRoute;
diff --git a/client/src/Components/Sidebar/index.jsx b/client/src/Components/Sidebar/index.jsx
index e9f0d3ad7..219ceff1e 100644
--- a/client/src/Components/Sidebar/index.jsx
+++ b/client/src/Components/Sidebar/index.jsx
@@ -49,6 +49,8 @@ import { useDispatch, useSelector } from "react-redux";
import { useTranslation } from "react-i18next";
import { clearAuthState } from "../../Features/Auth/authSlice";
import { toggleSidebar } from "../../Features/UI/uiSlice";
+import { TurnedIn } from "@mui/icons-material";
+import { rules } from "eslint-plugin-react-refresh";
const getMenu = (t) => [
{ name: t("menu.uptime"), path: "uptime", icon: },
@@ -121,7 +123,6 @@ function Sidebar() {
const { t } = useTranslation();
const authState = useSelector((state) => state.auth);
- const menu = getMenu(t);
const otherMenuItems = getOtherMenuItems(t);
const accountMenuItems = getAccountMenuItems(t);
const collapsed = useSelector((state) => state.ui.sidebar.collapsed);
@@ -133,6 +134,13 @@ function Sidebar() {
const sidebarRef = useRef(null);
const [sidebarReady, setSidebarReady] = useState(false);
const TRANSITION_DURATION = 200;
+ let menu = getMenu(t);
+ menu = menu.filter((item) => {
+ if (item.path === "logs") {
+ return user.role?.includes("admin") || user.role?.includes("superadmin");
+ }
+ return true;
+ });
useEffect(() => {
if (!collapsed) {
diff --git a/client/src/Components/TabPanels/Account/TeamPanel.jsx b/client/src/Components/TabPanels/Account/TeamPanel.jsx
index 341f84ba7..45578cc6c 100644
--- a/client/src/Components/TabPanels/Account/TeamPanel.jsx
+++ b/client/src/Components/TabPanels/Account/TeamPanel.jsx
@@ -168,7 +168,7 @@ const TeamPanel = () => {
});
} catch (error) {
createToast({
- body: error.message || "Unknown error.",
+ body: error?.response?.data?.msg || error.message || "Unknown error.",
});
} finally {
setIsSendingInvite(false);
@@ -268,7 +268,7 @@ const TeamPanel = () => {
value={toInvite.email}
onChange={handleChange}
error={errors.email ? true : false}
- helperText={errors.email}
+ helperText={t(errors.email)}
/>