From fc9018e314bc7de0724c05070ff649a01a0e22f2 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 27 Sep 2025 15:47:56 -0700 Subject: [PATCH 1/9] Add collapse button and logo --- client/src/Components/v2/Arrows/ArrowLeft.tsx | 36 +++++++++++ .../src/Components/v2/Arrows/ArrowRight.tsx | 28 +++++++++ .../src/Components/v2/Layouts/RootLayout.tsx | 35 +---------- .../v2/Layouts/Sidebar/CollapseButton.tsx | 50 ++++++++++++++++ .../Components/v2/Layouts/Sidebar/Logo.tsx | 59 +++++++++++++++++++ .../Components/v2/Layouts/Sidebar/index.tsx | 40 +++++++++++++ client/src/Features/UI/uiSlice.js | 5 ++ client/src/Utils/Theme/v2/palette.ts | 10 ++++ client/src/Utils/Theme/v2/theme.ts | 3 + client/src/types/env.d.ts | 8 +++ client/src/types/mui.d.ts | 3 + 11 files changed, 243 insertions(+), 34 deletions(-) create mode 100644 client/src/Components/v2/Arrows/ArrowLeft.tsx create mode 100644 client/src/Components/v2/Arrows/ArrowRight.tsx create mode 100644 client/src/Components/v2/Layouts/Sidebar/CollapseButton.tsx create mode 100644 client/src/Components/v2/Layouts/Sidebar/Logo.tsx create mode 100644 client/src/Components/v2/Layouts/Sidebar/index.tsx diff --git a/client/src/Components/v2/Arrows/ArrowLeft.tsx b/client/src/Components/v2/Arrows/ArrowLeft.tsx new file mode 100644 index 000000000..01d1342c8 --- /dev/null +++ b/client/src/Components/v2/Arrows/ArrowLeft.tsx @@ -0,0 +1,36 @@ +import LeftArrow from "@/assets/icons/left-arrow.svg?react"; +import LeftArrowDouble from "@/assets/icons/left-arrow-double.svg?react"; +import LeftArrowLong from "@/assets/icons/left-arrow-long.svg?react"; + +export const ArrowLeft = ({ + type, + color = "#667085", + ...props +}: { + type?: string; + color?: string | undefined; + [key: string]: any; +}) => { + if (type === "double") { + return ( + + ); + } else if (type === "long") { + return ( + + ); + } else { + return ( + + ); + } +}; diff --git a/client/src/Components/v2/Arrows/ArrowRight.tsx b/client/src/Components/v2/Arrows/ArrowRight.tsx new file mode 100644 index 000000000..c73165f16 --- /dev/null +++ b/client/src/Components/v2/Arrows/ArrowRight.tsx @@ -0,0 +1,28 @@ +import RightArrow from "@/assets/icons/right-arrow.svg?react"; +import RightArrowDouble from "@/assets/icons/right-arrow-double.svg?react"; + +export const ArrowRight = ({ + type, + color = "#667085", + ...props +}: { + type?: string; + color?: string | undefined; + [key: string]: any; +}) => { + if (type === "double") { + return ( + + ); + } else { + return ( + + ); + } +}; diff --git a/client/src/Components/v2/Layouts/RootLayout.tsx b/client/src/Components/v2/Layouts/RootLayout.tsx index be2f42e30..dbc6f2e5e 100644 --- a/client/src/Components/v2/Layouts/RootLayout.tsx +++ b/client/src/Components/v2/Layouts/RootLayout.tsx @@ -1,39 +1,6 @@ -import { useState, useEffect } from "react"; -import useMediaQuery from "@mui/material/useMediaQuery"; -import { useTheme } from "@mui/material/styles"; - import { Outlet } from "react-router"; import Stack from "@mui/material/Stack"; -import Box from "@mui/material/Box"; - -const COLLAPSED_WIDTH = 50; -const EXPANDED_WIDTH = 250; - -const SideBar = () => { - const theme = useTheme(); - const isSmall = useMediaQuery(theme.breakpoints.down("md")); - - const [collapsed, setCollapsed] = useState(false); - useEffect(() => { - setCollapsed(isSmall); - }, [isSmall]); - return ( - - setCollapsed(!collapsed)} - > - Sidebar Content - - - ); -}; +import { SideBar } from "@/Components/v2/Layouts/Sidebar"; const RootLayout = () => { return ( diff --git a/client/src/Components/v2/Layouts/Sidebar/CollapseButton.tsx b/client/src/Components/v2/Layouts/Sidebar/CollapseButton.tsx new file mode 100644 index 000000000..564c41591 --- /dev/null +++ b/client/src/Components/v2/Layouts/Sidebar/CollapseButton.tsx @@ -0,0 +1,50 @@ +import IconButton from "@mui/material/IconButton"; +import { ArrowRight } from "@/Components/v2/Arrows/ArrowRight"; +import { ArrowLeft } from "@/Components/v2/Arrows/ArrowLeft"; +import { useTheme } from "@mui/material/styles"; +import { useDispatch } from "react-redux"; +import { toggleSidebar } from "../../../../Features/UI/uiSlice.js"; + +export const CollapseButton = ({ collapsed }: { collapsed: boolean }) => { + const theme = useTheme(); + const dispatch = useDispatch(); + const arrowIcon = collapsed ? ( + + ) : ( + + ); + + return ( + { + dispatch(toggleSidebar()); + }} + > + {arrowIcon} + + ); +}; diff --git a/client/src/Components/v2/Layouts/Sidebar/Logo.tsx b/client/src/Components/v2/Layouts/Sidebar/Logo.tsx new file mode 100644 index 000000000..6d190b99d --- /dev/null +++ b/client/src/Components/v2/Layouts/Sidebar/Logo.tsx @@ -0,0 +1,59 @@ +import Stack from "@mui/material/Stack"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import { useTheme } from "@mui/material/styles"; +import { useNavigate } from "react-router"; +import { useTranslation } from "react-i18next"; + +export const Logo = ({ collapsed }: { collapsed: boolean }) => { + const { t } = useTranslation(); + const theme = useTheme(); + const navigate = useNavigate(); + + return ( + navigate("/")} + sx={{ cursor: "pointer" }} + > + + C + + + {" "} + + {t("common.appName")} + + + + ); +}; diff --git a/client/src/Components/v2/Layouts/Sidebar/index.tsx b/client/src/Components/v2/Layouts/Sidebar/index.tsx new file mode 100644 index 000000000..43975adfc --- /dev/null +++ b/client/src/Components/v2/Layouts/Sidebar/index.tsx @@ -0,0 +1,40 @@ +import { useEffect } from "react"; +import { useSelector, useDispatch } from "react-redux"; +import { setCollapsed } from "@/Features/UI/uiSlice"; +import useMediaQuery from "@mui/material/useMediaQuery"; +import { useTheme } from "@mui/material/styles"; + +import { CollapseButton } from "@/Components/v2/Layouts/Sidebar/CollapseButton"; +import Stack from "@mui/material/Stack"; +import { Logo } from "@/Components/v2/Layouts/Sidebar/Logo"; + +export const COLLAPSED_WIDTH = 64; +export const EXPANDED_WIDTH = 250; + +export const SideBar = () => { + const theme = useTheme(); + const isSmall = useMediaQuery(theme.breakpoints.down("md")); + const dispatch = useDispatch(); + const collapsed = useSelector((state: any) => state.ui.sidebar.collapsed); + + useEffect(() => { + dispatch(setCollapsed({ collapsed: isSmall })); + }, [isSmall]); + + return ( + + + + + ); +}; diff --git a/client/src/Features/UI/uiSlice.js b/client/src/Features/UI/uiSlice.js index 45ba267b0..63f7ae90e 100644 --- a/client/src/Features/UI/uiSlice.js +++ b/client/src/Features/UI/uiSlice.js @@ -47,6 +47,10 @@ const uiSlice = createSlice({ toggleSidebar: (state) => { state.sidebar.collapsed = !state.sidebar.collapsed; }, + setCollapsed: (state, action) => { + const { collapsed } = action.payload; + state.sidebar.collapsed = collapsed; + }, setMode: (state, action) => { state.mode = action.payload; }, @@ -73,6 +77,7 @@ export default uiSlice.reducer; export const { setRowsPerPage, toggleSidebar, + setCollapsed, setMode, setShowURL, setGreeting, diff --git a/client/src/Utils/Theme/v2/palette.ts b/client/src/Utils/Theme/v2/palette.ts index 2875f750d..2e41a159c 100644 --- a/client/src/Utils/Theme/v2/palette.ts +++ b/client/src/Utils/Theme/v2/palette.ts @@ -54,12 +54,17 @@ export const lightPalette = { main: colors.offWhite, contrastText: colors.blueGray800, contrastTextSecondary: colors.blueGray600, + lowContrast: colors.gray250, }, secondary: { main: colors.gray200, light: colors.lightBlueWave, contrastText: colors.blueGray600, }, + tertiary: { + main: colors.gray100, + contrastText: colors.blueGray800, + }, }; export const darkPalette = { @@ -73,10 +78,15 @@ export const darkPalette = { main: colors.offBlack, contrastText: colors.blueGray50, contrastTextSecondary: colors.gray200, + lowContrast: colors.blueGray600, }, secondary: { main: "#313131", light: colors.lightBlueWave, contrastText: colors.gray200, }, + tertiary: { + main: colors.blueGray800, + contrastText: colors.gray100, + }, }; diff --git a/client/src/Utils/Theme/v2/theme.ts b/client/src/Utils/Theme/v2/theme.ts index 55d2b9bb9..77bab3e70 100644 --- a/client/src/Utils/Theme/v2/theme.ts +++ b/client/src/Utils/Theme/v2/theme.ts @@ -67,6 +67,9 @@ export const theme = (mode: string, palette: any) => }, }, }, + shape: { + borderRadius: 2, + }, }); export const lightTheme = createTheme(theme("light", lightPalette)); diff --git a/client/src/types/env.d.ts b/client/src/types/env.d.ts index e2bce23dd..74a2a29e7 100644 --- a/client/src/types/env.d.ts +++ b/client/src/types/env.d.ts @@ -7,3 +7,11 @@ interface ImportMetaEnv { interface ImportMeta { readonly env: ImportMetaEnv; } + +declare module "*.svg?react" { + import * as React from "react"; + const ReactComponent: React.FunctionComponent< + React.SVGProps & { title?: string } + >; + export default ReactComponent; +} diff --git a/client/src/types/mui.d.ts b/client/src/types/mui.d.ts index 851ffea70..5f5c1c38b 100644 --- a/client/src/types/mui.d.ts +++ b/client/src/types/mui.d.ts @@ -3,13 +3,16 @@ import "@mui/material/Button"; declare module "@mui/material/styles" { interface Palette { accent: Palette["primary"]; + tertiary: Palette["primary"]; } interface PaletteOptions { accent?: PaletteOptions["primary"]; + tertiary?: PaletteOptions["primary"]; } interface PaletteColor { contrastTextSecondary?: string; + lowContrast?: string; } } From 7f2318da01a21f47216f666ebdd8192b48fe6b2a Mon Sep 17 00:00:00 2001 From: ariretiarno Date: Tue, 30 Sep 2025 11:28:22 +0700 Subject: [PATCH 2/9] helm chart --- .../templates/client-deployment.yaml | 8 ++-- .../checkmate/templates/client-ingress.yaml | 9 ++++- .../checkmate/templates/client-service.yaml | 4 +- .../helm/checkmate/templates/mongodb-pvc.yaml | 10 ----- .../checkmate/templates/mongodb-service.yaml | 4 +- ...loyment.yaml => mongodb-statefulsets.yaml} | 21 ++++++---- .../checkmate/templates/redis-deployment.yaml | 26 ------------- .../helm/checkmate/templates/redis-pvc.yaml | 10 ----- .../checkmate/templates/redis-service.yaml | 6 ++- .../templates/redis-statefulsets.yaml | 33 ++++++++++++++++ .../templates/server-deployment.yaml | 6 +-- .../checkmate/templates/server-ingress.yaml | 21 ++++++---- .../checkmate/templates/server-service.yaml | 4 +- charts/helm/checkmate/values.yaml | 38 +++++++++++-------- 14 files changed, 107 insertions(+), 93 deletions(-) delete mode 100644 charts/helm/checkmate/templates/mongodb-pvc.yaml rename charts/helm/checkmate/templates/{mongodb-deployment.yaml => mongodb-statefulsets.yaml} (54%) delete mode 100644 charts/helm/checkmate/templates/redis-deployment.yaml delete mode 100644 charts/helm/checkmate/templates/redis-pvc.yaml create mode 100644 charts/helm/checkmate/templates/redis-statefulsets.yaml diff --git a/charts/helm/checkmate/templates/client-deployment.yaml b/charts/helm/checkmate/templates/client-deployment.yaml index 6c1f70fd7..b6e13fc7d 100644 --- a/charts/helm/checkmate/templates/client-deployment.yaml +++ b/charts/helm/checkmate/templates/client-deployment.yaml @@ -1,16 +1,16 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: client + name: checkmate-client spec: replicas: 1 selector: matchLabels: - app: client + app: checkmate-client template: metadata: labels: - app: client + app: checkmate-client spec: containers: - name: client @@ -20,3 +20,5 @@ spec: env: - name: UPTIME_APP_API_BASE_URL value: "{{ .Values.server.protocol }}://{{ .Values.server.ingress.host }}/api/v1" + - name: UPTIME_APP_CLIENT_HOST + value: "http://{{ .Values.client.ingress.host }}" diff --git a/charts/helm/checkmate/templates/client-ingress.yaml b/charts/helm/checkmate/templates/client-ingress.yaml index da059a863..014aa53b3 100644 --- a/charts/helm/checkmate/templates/client-ingress.yaml +++ b/charts/helm/checkmate/templates/client-ingress.yaml @@ -2,10 +2,15 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: client-ingress + name: checkmate-client-ingress + {{- if .Values.client.ingress.annotations }} annotations: - nginx.ingress.kubernetes.io/rewrite-target: / + {{- range $key, $value := .Values.client.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} spec: + ingressClassName: {{ .Values.client.ingress.className }} rules: - host: {{ .Values.client.ingress.host }} http: diff --git a/charts/helm/checkmate/templates/client-service.yaml b/charts/helm/checkmate/templates/client-service.yaml index afb88188c..b56eaeedf 100644 --- a/charts/helm/checkmate/templates/client-service.yaml +++ b/charts/helm/checkmate/templates/client-service.yaml @@ -1,9 +1,9 @@ apiVersion: v1 kind: Service metadata: - name: client + name: checkmate-client spec: selector: - app: client + app: checkmate-client ports: - port: {{ .Values.client.port }} diff --git a/charts/helm/checkmate/templates/mongodb-pvc.yaml b/charts/helm/checkmate/templates/mongodb-pvc.yaml deleted file mode 100644 index 435b662e6..000000000 --- a/charts/helm/checkmate/templates/mongodb-pvc.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: mongodb-pvc -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ .Values.persistence.mongodbSize }} \ No newline at end of file diff --git a/charts/helm/checkmate/templates/mongodb-service.yaml b/charts/helm/checkmate/templates/mongodb-service.yaml index 2911dc3eb..b96fe1a82 100644 --- a/charts/helm/checkmate/templates/mongodb-service.yaml +++ b/charts/helm/checkmate/templates/mongodb-service.yaml @@ -1,9 +1,9 @@ apiVersion: v1 kind: Service metadata: - name: mongodb + name: checkmate-mongodb spec: selector: - app: mongodb + app: checkmate-mongodb ports: - port: {{ .Values.mongodb.port }} \ No newline at end of file diff --git a/charts/helm/checkmate/templates/mongodb-deployment.yaml b/charts/helm/checkmate/templates/mongodb-statefulsets.yaml similarity index 54% rename from charts/helm/checkmate/templates/mongodb-deployment.yaml rename to charts/helm/checkmate/templates/mongodb-statefulsets.yaml index 4c906fe09..4b490d7d7 100644 --- a/charts/helm/checkmate/templates/mongodb-deployment.yaml +++ b/charts/helm/checkmate/templates/mongodb-statefulsets.yaml @@ -1,16 +1,16 @@ apiVersion: apps/v1 -kind: Deployment +kind: StatefulSet metadata: - name: mongodb + name: checkmate-mongodb spec: replicas: 1 selector: matchLabels: - app: mongodb + app: checkmate-mongodb template: metadata: labels: - app: mongodb + app: checkmate-mongodb spec: containers: - name: mongodb @@ -21,7 +21,12 @@ spec: volumeMounts: - name: mongodb-data mountPath: /data/db - volumes: - - name: mongodb-data - persistentVolumeClaim: - claimName: mongodb-pvc \ No newline at end of file + volumeClaimTemplates: + - metadata: + name: checkmate-mongo-persistent-storage + spec: + storageClassName: "gp3" + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: {{ .Values.persistence.mongodbSize }} \ No newline at end of file diff --git a/charts/helm/checkmate/templates/redis-deployment.yaml b/charts/helm/checkmate/templates/redis-deployment.yaml deleted file mode 100644 index cc9ffdaf9..000000000 --- a/charts/helm/checkmate/templates/redis-deployment.yaml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: redis -spec: - replicas: 1 - selector: - matchLabels: - app: redis - template: - metadata: - labels: - app: redis - spec: - containers: - - name: redis - image: {{ .Values.redis.image }} - ports: - - containerPort: {{ .Values.redis.port }} - volumeMounts: - - name: redis-data - mountPath: /data - volumes: - - name: redis-data - persistentVolumeClaim: - claimName: redis-pvc diff --git a/charts/helm/checkmate/templates/redis-pvc.yaml b/charts/helm/checkmate/templates/redis-pvc.yaml deleted file mode 100644 index 2f0d81960..000000000 --- a/charts/helm/checkmate/templates/redis-pvc.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: redis-pvc -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ .Values.persistence.redisSize }} \ No newline at end of file diff --git a/charts/helm/checkmate/templates/redis-service.yaml b/charts/helm/checkmate/templates/redis-service.yaml index f29fa46de..2720350da 100644 --- a/charts/helm/checkmate/templates/redis-service.yaml +++ b/charts/helm/checkmate/templates/redis-service.yaml @@ -1,9 +1,11 @@ +{{- if .Values.redis.enabled }} apiVersion: v1 kind: Service metadata: - name: redis + name: checkmate-redis spec: selector: - app: redis + app: checkmate-redis ports: - port: {{ .Values.redis.port }} +{{- end }} diff --git a/charts/helm/checkmate/templates/redis-statefulsets.yaml b/charts/helm/checkmate/templates/redis-statefulsets.yaml new file mode 100644 index 000000000..252361730 --- /dev/null +++ b/charts/helm/checkmate/templates/redis-statefulsets.yaml @@ -0,0 +1,33 @@ +{{- if .Values.redis.enabled }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: checkmate-redis +spec: + replicas: 1 + selector: + matchLabels: + app: checkmate-redis + template: + metadata: + labels: + app: checkmate-redis + spec: + containers: + - name: redis + image: {{ .Values.redis.image }} + ports: + - containerPort: {{ .Values.redis.port }} + volumeMounts: + - name: redis-data + mountPath: /data + volumeClaimTemplates: + - metadata: + name: checkmate-redis-persistent-storage + spec: + storageClassName: "gp3" + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: {{ .Values.persistence.redisSize }} +{{- end }} \ No newline at end of file diff --git a/charts/helm/checkmate/templates/server-deployment.yaml b/charts/helm/checkmate/templates/server-deployment.yaml index 6f21f86f3..19affe8d8 100644 --- a/charts/helm/checkmate/templates/server-deployment.yaml +++ b/charts/helm/checkmate/templates/server-deployment.yaml @@ -1,16 +1,16 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: server + name: checkmate-server spec: replicas: 1 selector: matchLabels: - app: server + app: checkmate-server template: metadata: labels: - app: server + app: checkmate-server spec: containers: - name: server diff --git a/charts/helm/checkmate/templates/server-ingress.yaml b/charts/helm/checkmate/templates/server-ingress.yaml index c1982d451..3755c94b8 100644 --- a/charts/helm/checkmate/templates/server-ingress.yaml +++ b/charts/helm/checkmate/templates/server-ingress.yaml @@ -2,15 +2,22 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: server-ingress + name: checkmate-server-ingress + {{- if .Values.server.ingress.annotations }} annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - nginx.ingress.kubernetes.io/enable-cors: "true" - nginx.ingress.kubernetes.io/cors-allow-origin: "http://{{ .Values.client.ingress.host }},https://{{ .Values.client.ingress.host }}" - nginx.ingress.kubernetes.io/cors-allow-methods: "GET, PUT, POST, DELETE, PATCH, OPTIONS" - nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" - nginx.ingress.kubernetes.io/cors-allow-credentials: "true" + {{- range $key, $value := .Values.server.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} + {{/*#annotations: + #nginx.ingress.kubernetes.io/rewrite-target: / + #nginx.ingress.kubernetes.io/enable-cors: "true" + #nginx.ingress.kubernetes.io/cors-allow-origin: "http://{{ .Values.client.ingress.host }},https://{{ .Values.client.ingress.host }}" + #nginx.ingress.kubernetes.io/cors-allow-methods: "GET, PUT, POST, DELETE, PATCH, OPTIONS" + #nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" + #nginx.ingress.kubernetes.io/cors-allow-credentials: "true"*/}} spec: + ingressClassName: {{ .Values.server.ingress.className }} rules: - host: {{ .Values.server.ingress.host }} http: diff --git a/charts/helm/checkmate/templates/server-service.yaml b/charts/helm/checkmate/templates/server-service.yaml index 64494ff90..d8a7fbe86 100644 --- a/charts/helm/checkmate/templates/server-service.yaml +++ b/charts/helm/checkmate/templates/server-service.yaml @@ -1,9 +1,9 @@ apiVersion: v1 kind: Service metadata: - name: server + name: checkmate-server spec: selector: - app: server + app: checkmate-server ports: - port: {{ .Values.server.port }} diff --git a/charts/helm/checkmate/values.yaml b/charts/helm/checkmate/values.yaml index 79c77a49e..1840cf909 100644 --- a/charts/helm/checkmate/values.yaml +++ b/charts/helm/checkmate/values.yaml @@ -1,40 +1,46 @@ client: - image: ghcr.io/bluewave-labs/checkmate-client:v2.3 + image: ghcr.io/bluewave-labs/checkmate-client:v3.2.0 port: 80 ingress: enabled: true host: change_me + className: nginx + annotations: {} server: - image: ghcr.io/bluewave-labs/checkmate-backend:v2.3 + image: ghcr.io/bluewave-labs/checkmate-backend:v3.2.0 port: 52345 - protocol: change_me + protocol: http ingress: enabled: true host: change_me + className: nginx + annotations: {} redis: + enabled: false image: redis:7.2 port: 6379 mongodb: - image: mongo:7.0 + image: ghcr.io/bluewave-labs/checkmate-mongo:v3.2.0 port: 27017 secrets: JWT_SECRET: change_me - REFRESH_TOKEN_SECRET: change_me - SYSTEM_EMAIL_ADDRESS: test@example.com - SYSTEM_EMAIL_PASSWORD: change_me - SYSTEM_EMAIL_HOST: smtp.example.com - SYSTEM_EMAIL_PORT: "587" - PAGESPEED_API_KEY: change_me - DB_CONNECTION_STRING: mongodb://mongodb:27017/uptime_db - REDIS_HOST: redis - REDIS_PORT: "6379" - DB_TYPE: MongoDB - TOKEN_TTL: 99d - REFRESH_TOKEN_TTL: 99d +# REFRESH_TOKEN_SECRET: change_me +# SYSTEM_EMAIL_ADDRESS: test@example.com +# SYSTEM_EMAIL_PASSWORD: change_me +# SYSTEM_EMAIL_HOST: smtp.example.com +# SYSTEM_EMAIL_PORT: "587" +# PAGESPEED_API_KEY: change_me + DB_CONNECTION_STRING: mongodb://checkmate-mongodb.namespace.svc:27017/uptime_db + CLIENT_HOST: change_me +# REDIS_HOST: redis +# REDIS_PORT: "6379" +# DB_TYPE: MongoDB +# TOKEN_TTL: 99d +# REFRESH_TOKEN_TTL: 99d persistence: mongodbSize: 5Gi From c6cf7a46391a9608156c385e0f626d922e6b2e90 Mon Sep 17 00:00:00 2001 From: ariretiarno Date: Tue, 30 Sep 2025 11:30:21 +0700 Subject: [PATCH 3/9] helm chart --- charts/helm/checkmate/templates/secrets.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/charts/helm/checkmate/templates/secrets.yaml b/charts/helm/checkmate/templates/secrets.yaml index 0a3f1ace5..af104e7d1 100644 --- a/charts/helm/checkmate/templates/secrets.yaml +++ b/charts/helm/checkmate/templates/secrets.yaml @@ -4,10 +4,6 @@ {{- fail "secrets.JWT_SECRET must be overridden and cannot be 'change_me'" }} {{- end }} -{{- if or (not $secrets.REFRESH_TOKEN_SECRET) (eq $secrets.REFRESH_TOKEN_SECRET "change_me") }} - {{- fail "secrets.REFRESH_TOKEN_SECRET must be overridden and cannot be 'change_me'" }} -{{- end }} - apiVersion: v1 kind: Secret metadata: From 4744c05f07669a0110ae634d26f756c38d88c633 Mon Sep 17 00:00:00 2001 From: ariretiarno Date: Tue, 30 Sep 2025 11:35:14 +0700 Subject: [PATCH 4/9] pvc --- charts/helm/checkmate/templates/mongodb-statefulsets.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/helm/checkmate/templates/mongodb-statefulsets.yaml b/charts/helm/checkmate/templates/mongodb-statefulsets.yaml index 4b490d7d7..1ffd1c228 100644 --- a/charts/helm/checkmate/templates/mongodb-statefulsets.yaml +++ b/charts/helm/checkmate/templates/mongodb-statefulsets.yaml @@ -19,7 +19,7 @@ spec: - containerPort: {{ .Values.mongodb.port }} command: ["mongod", "--quiet", "--bind_ip_all"] volumeMounts: - - name: mongodb-data + - name: checkmate-mongo-persistent-storage mountPath: /data/db volumeClaimTemplates: - metadata: From 7a352cdcb34a962798dae4f03c1a073809b5addf Mon Sep 17 00:00:00 2001 From: ariretiarno Date: Wed, 1 Oct 2025 09:16:45 +0700 Subject: [PATCH 5/9] client host --- charts/helm/checkmate/server-nginx-cm.yaml | 41 +++++++++++++++++++ .../templates/server-deployment.yaml | 3 ++ 2 files changed, 44 insertions(+) create mode 100644 charts/helm/checkmate/server-nginx-cm.yaml diff --git a/charts/helm/checkmate/server-nginx-cm.yaml b/charts/helm/checkmate/server-nginx-cm.yaml new file mode 100644 index 000000000..64eca82b7 --- /dev/null +++ b/charts/helm/checkmate/server-nginx-cm.yaml @@ -0,0 +1,41 @@ +apiVersion: apps/v1 +kind: ConfigMap +metadata: + name: checkmate-server-nginx-cm +data: + default.conf: | + server { + listen 80; + listen [::]:80; + + server_name checkmate-demo.bluewavelabs.ca; + server_tokens off; + + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + # location /api/ { + # proxy_pass http://server:5000/api/; + # proxy_http_version 1.1; + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header X-Forwarded-Proto $scheme; + # } + + location /api-docs/ { + proxy_pass http://server:5000/api-docs/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + } \ No newline at end of file diff --git a/charts/helm/checkmate/templates/server-deployment.yaml b/charts/helm/checkmate/templates/server-deployment.yaml index 19affe8d8..856e16922 100644 --- a/charts/helm/checkmate/templates/server-deployment.yaml +++ b/charts/helm/checkmate/templates/server-deployment.yaml @@ -20,3 +20,6 @@ spec: envFrom: - secretRef: name: checkmate-secrets + env: + - name: CLIENT_HOST + value: {{ .Values.client.ingress.host }} From d63731fcedcab31c58a94121e4d93dcfe21559ab Mon Sep 17 00:00:00 2001 From: ariretiarno Date: Wed, 1 Oct 2025 09:22:42 +0700 Subject: [PATCH 6/9] client host --- charts/helm/checkmate/templates/server-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/helm/checkmate/templates/server-deployment.yaml b/charts/helm/checkmate/templates/server-deployment.yaml index 856e16922..8c9403916 100644 --- a/charts/helm/checkmate/templates/server-deployment.yaml +++ b/charts/helm/checkmate/templates/server-deployment.yaml @@ -22,4 +22,4 @@ spec: name: checkmate-secrets env: - name: CLIENT_HOST - value: {{ .Values.client.ingress.host }} + value: "http://{{ .Values.client.ingress.host }}" From 8d48b2cc8a8c24e1c9c5af4f512708fa70dfe463 Mon Sep 17 00:00:00 2001 From: ariretiarno Date: Wed, 1 Oct 2025 09:33:32 +0700 Subject: [PATCH 7/9] client host --- charts/helm/checkmate/templates/client-deployment.yaml | 8 ++++++++ charts/helm/checkmate/templates/client-ingress.yaml | 2 +- charts/helm/checkmate/templates/server-ingress.yaml | 2 +- .../helm/checkmate/{ => templates}/server-nginx-cm.yaml | 6 +++--- 4 files changed, 13 insertions(+), 5 deletions(-) rename charts/helm/checkmate/{ => templates}/server-nginx-cm.yaml (86%) diff --git a/charts/helm/checkmate/templates/client-deployment.yaml b/charts/helm/checkmate/templates/client-deployment.yaml index b6e13fc7d..a5d487dc8 100644 --- a/charts/helm/checkmate/templates/client-deployment.yaml +++ b/charts/helm/checkmate/templates/client-deployment.yaml @@ -22,3 +22,11 @@ spec: value: "{{ .Values.server.protocol }}://{{ .Values.server.ingress.host }}/api/v1" - name: UPTIME_APP_CLIENT_HOST value: "http://{{ .Values.client.ingress.host }}" + volumeMounts: + - name: config-volume + mountPath: /etc/nginx/conf.d/default.conf + subPath: default.conf + volumes: + - name: config-volume + configMap: + name: checkmate-server-nginx-cm diff --git a/charts/helm/checkmate/templates/client-ingress.yaml b/charts/helm/checkmate/templates/client-ingress.yaml index 014aa53b3..89e001e15 100644 --- a/charts/helm/checkmate/templates/client-ingress.yaml +++ b/charts/helm/checkmate/templates/client-ingress.yaml @@ -19,7 +19,7 @@ spec: pathType: Prefix backend: service: - name: client + name: checkmate-client port: number: {{ .Values.client.port }} {{- end }} diff --git a/charts/helm/checkmate/templates/server-ingress.yaml b/charts/helm/checkmate/templates/server-ingress.yaml index 3755c94b8..0d7ca867b 100644 --- a/charts/helm/checkmate/templates/server-ingress.yaml +++ b/charts/helm/checkmate/templates/server-ingress.yaml @@ -26,7 +26,7 @@ spec: pathType: Prefix backend: service: - name: server + name: checkmate-server port: number: {{ .Values.server.port }} {{- end }} diff --git a/charts/helm/checkmate/server-nginx-cm.yaml b/charts/helm/checkmate/templates/server-nginx-cm.yaml similarity index 86% rename from charts/helm/checkmate/server-nginx-cm.yaml rename to charts/helm/checkmate/templates/server-nginx-cm.yaml index 64eca82b7..84da55299 100644 --- a/charts/helm/checkmate/server-nginx-cm.yaml +++ b/charts/helm/checkmate/templates/server-nginx-cm.yaml @@ -1,4 +1,4 @@ -apiVersion: apps/v1 +apiVersion: v1 kind: ConfigMap metadata: name: checkmate-server-nginx-cm @@ -22,7 +22,7 @@ data: } # location /api/ { - # proxy_pass http://server:5000/api/; + # proxy_pass http://{{ .Values.server.ingress.host }}:5000/api/; # proxy_http_version 1.1; # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; @@ -31,7 +31,7 @@ data: # } location /api-docs/ { - proxy_pass http://server:5000/api-docs/; + proxy_pass http://{{ .Values.server.ingress.host }}:5000/api-docs/; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; From 3ae2f857d4169f13cec49166dae0dd42ed9776ed Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 1 Oct 2025 13:55:32 -0700 Subject: [PATCH 8/9] add v2 sidebar --- .../v2/Layouts/Sidebar/BottomControls.tsx | 16 +++ .../Components/v2/Layouts/Sidebar/Menu.tsx | 58 ++++++++++ .../Components/v2/Layouts/Sidebar/NavItem.tsx | 103 ++++++++++++++++++ .../Components/v2/Layouts/Sidebar/index.tsx | 65 ++++++++++- client/src/Features/Auth/v2AuthSlice.ts | 19 ++++ client/src/Pages/v2/Auth/Login.tsx | 11 +- client/src/Routes/v2router.tsx | 6 +- client/src/Utils/Theme/v2/palette.ts | 2 + client/src/store.js | 4 +- client/src/types/mui.d.ts | 1 + 10 files changed, 279 insertions(+), 6 deletions(-) create mode 100644 client/src/Components/v2/Layouts/Sidebar/BottomControls.tsx create mode 100644 client/src/Components/v2/Layouts/Sidebar/Menu.tsx create mode 100644 client/src/Components/v2/Layouts/Sidebar/NavItem.tsx create mode 100644 client/src/Features/Auth/v2AuthSlice.ts diff --git a/client/src/Components/v2/Layouts/Sidebar/BottomControls.tsx b/client/src/Components/v2/Layouts/Sidebar/BottomControls.tsx new file mode 100644 index 000000000..a07ccde6c --- /dev/null +++ b/client/src/Components/v2/Layouts/Sidebar/BottomControls.tsx @@ -0,0 +1,16 @@ +import { useTheme } from "@mui/material/styles"; + +import Stack from "@mui/material/Stack"; + +export const BottomControls = ({}) => { + const theme = useTheme(); + return ( + + ); +}; diff --git a/client/src/Components/v2/Layouts/Sidebar/Menu.tsx b/client/src/Components/v2/Layouts/Sidebar/Menu.tsx new file mode 100644 index 000000000..5b3ed705e --- /dev/null +++ b/client/src/Components/v2/Layouts/Sidebar/Menu.tsx @@ -0,0 +1,58 @@ +import Notifications from "@/assets/icons/notifications.svg?react"; +import Monitors from "@/assets/icons/monitors.svg?react"; +import PageSpeed from "@/assets/icons/page-speed.svg?react"; +import Integrations from "@/assets/icons/integrations.svg?react"; +import Incidents from "@/assets/icons/incidents.svg?react"; +import StatusPages from "@/assets/icons/status-pages.svg?react"; +import Maintenance from "@/assets/icons/maintenance.svg?react"; +import Logs from "@/assets/icons/logs.svg?react"; +import Settings from "@/assets/icons/settings.svg?react"; +import Support from "@/assets/icons/support.svg?react"; +import Discussions from "@/assets/icons/discussions.svg?react"; +import Docs from "@/assets/icons/docs.svg?react"; +import ChangeLog from "@/assets/icons/changeLog.svg?react"; + +export const getMenu = (t: Function) => [ + { name: t("menu.uptime"), path: "v2/uptime", icon: }, + { name: t("menu.pagespeed"), path: "pagespeed", icon: }, + + { name: t("menu.infrastructure"), path: "infrastructure", icon: }, + { + name: t("menu.notifications"), + path: "notifications", + icon: , + }, + { name: t("menu.incidents"), path: "incidents", icon: }, + + { name: t("menu.statusPages"), path: "status", icon: }, + { name: t("menu.maintenance"), path: "maintenance", icon: }, + { name: t("menu.logs"), path: "logs", icon: }, + + { + name: t("menu.settings"), + icon: , + path: "settings", + }, +]; + +export const getBottomMenu = (t: Function) => [ + { name: t("menu.support"), path: "support", icon: , url: "invite" }, + { + name: t("menu.discussions"), + path: "discussions", + icon: , + url: "https://github.com/bluewave-labs/checkmate/discussions", + }, + { + name: t("menu.docs"), + path: "docs", + icon: , + url: "https://bluewavelabs.gitbook.io/checkmate", + }, + { + name: t("menu.changelog"), + path: "changelog", + icon: , + url: "https://github.com/bluewave-labs/checkmate/releases", + }, +]; diff --git a/client/src/Components/v2/Layouts/Sidebar/NavItem.tsx b/client/src/Components/v2/Layouts/Sidebar/NavItem.tsx new file mode 100644 index 000000000..8f7f5d68c --- /dev/null +++ b/client/src/Components/v2/Layouts/Sidebar/NavItem.tsx @@ -0,0 +1,103 @@ +import Tooltip from "@mui/material/Tooltip"; +import ListItemButton from "@mui/material/ListItemButton"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import { useTheme } from "@mui/material/styles"; + +export interface NavData { + name: string; + icon: JSX.Element; +} + +export const NavItem = ({ + item, + collapsed, + selected, + onClick, +}: { + item: NavData; + collapsed: boolean; + selected: boolean; + onClick: (event: React.MouseEvent) => void; +}) => { + const theme = useTheme(); + const iconStroke = selected + ? theme.palette.primary.contrastText + : theme.palette.primary.contrastTextTertiary; + + const buttonBgColor = selected ? theme.palette.secondary.main : "transparent"; + const buttonBgHoverColor = selected + ? theme.palette.secondary.main + : theme.palette.tertiary.main; + const fontWeight = selected ? 600 : 400; + return ( + + + + {item.icon} + + + + {item.name} + + + + + ); +}; diff --git a/client/src/Components/v2/Layouts/Sidebar/index.tsx b/client/src/Components/v2/Layouts/Sidebar/index.tsx index 43975adfc..b05716aee 100644 --- a/client/src/Components/v2/Layouts/Sidebar/index.tsx +++ b/client/src/Components/v2/Layouts/Sidebar/index.tsx @@ -3,10 +3,17 @@ import { useSelector, useDispatch } from "react-redux"; import { setCollapsed } from "@/Features/UI/uiSlice"; import useMediaQuery from "@mui/material/useMediaQuery"; import { useTheme } from "@mui/material/styles"; +import { useTranslation } from "react-i18next"; +import { useNavigate, useLocation } from "react-router-dom"; import { CollapseButton } from "@/Components/v2/Layouts/Sidebar/CollapseButton"; import Stack from "@mui/material/Stack"; +import List from "@mui/material/List"; +import Divider from "@mui/material/Divider"; import { Logo } from "@/Components/v2/Layouts/Sidebar/Logo"; +import { getMenu, getBottomMenu } from "@/Components/v2/Layouts/Sidebar/Menu"; +import { NavItem } from "@/Components/v2/Layouts/Sidebar/NavItem"; +import { BottomControls } from "@/Components/v2/Layouts/Sidebar/BottomControls"; export const COLLAPSED_WIDTH = 64; export const EXPANDED_WIDTH = 250; @@ -16,6 +23,11 @@ export const SideBar = () => { const isSmall = useMediaQuery(theme.breakpoints.down("md")); const dispatch = useDispatch(); const collapsed = useSelector((state: any) => state.ui.sidebar.collapsed); + const { t } = useTranslation(); + const navigate = useNavigate(); + const location = useLocation(); + const menu = getMenu(t); + const bottomMenu = getBottomMenu(t); useEffect(() => { dispatch(setCollapsed({ collapsed: isSmall })); @@ -23,6 +35,7 @@ export const SideBar = () => { return ( { borderRight={`1px solid ${theme.palette.primary.lowContrast}`} width={collapsed ? COLLAPSED_WIDTH : EXPANDED_WIDTH} sx={{ - transition: "width 0.3s ease", + transition: "width 650ms cubic-bezier(0.36, -0.01, 0, 0.77)", }} > + + {menu.map((item) => { + const selected = location.pathname.startsWith(`/${item.path}`); + return ( + navigate(`/${item.path}`)} + /> + ); + })} + + + {bottomMenu.map((item) => { + const selected = location.pathname.startsWith(`/${item.path}`); + + return ( + { + if (item.url) { + window.open(item.url, "_blank", "noreferrer"); + } else { + navigate(`/${item.path}`); + } + }} + /> + ); + })} + + + ); }; diff --git a/client/src/Features/Auth/v2AuthSlice.ts b/client/src/Features/Auth/v2AuthSlice.ts new file mode 100644 index 000000000..28a18b659 --- /dev/null +++ b/client/src/Features/Auth/v2AuthSlice.ts @@ -0,0 +1,19 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const initialState = { + isAuthenticated: false, +}; + +const v2AuthSlice = createSlice({ + name: "v2Auth", + initialState, + reducers: { + setIsAuthenticated: (state, action) => { + const { authenticated } = action.payload; + state.isAuthenticated = authenticated; + }, + }, +}); + +export default v2AuthSlice.reducer; +export const { setIsAuthenticated } = v2AuthSlice.actions; diff --git a/client/src/Pages/v2/Auth/Login.tsx b/client/src/Pages/v2/Auth/Login.tsx index fd4a08e93..2a5629917 100644 --- a/client/src/Pages/v2/Auth/Login.tsx +++ b/client/src/Pages/v2/Auth/Login.tsx @@ -3,7 +3,9 @@ import { z } from "zod"; import { useTranslation } from "react-i18next"; import { useForm, Controller } from "react-hook-form"; import { useTheme } from "@mui/material/styles"; - +import { useDispatch } from "react-redux"; +import { setIsAuthenticated } from "@/Features/Auth/v2AuthSlice"; +import { useNavigate } from "react-router"; import { TextInput } from "@/Components/v2/Inputs/TextInput"; import Button from "@mui/material/Button"; import Stack from "@mui/material/Stack"; @@ -19,8 +21,10 @@ type FormData = z.infer; const Login = () => { const { t } = useTranslation(); + const dispatch = useDispatch(); const theme = useTheme(); const { post, loading, error } = usePost("/auth/login"); + const navigate = useNavigate(); const { handleSubmit, @@ -37,9 +41,10 @@ const Login = () => { const onSubmit = async (data: FormData) => { const result = await post(data); if (result) { - console.log(result.message); + dispatch(setIsAuthenticated({ authenticated: true })); + navigate("/v2/uptime"); } else { - console.error("Login failed:", error); + dispatch(setIsAuthenticated({ authenticated: false })); } }; diff --git a/client/src/Routes/v2router.tsx b/client/src/Routes/v2router.tsx index 941550026..12d3eb595 100644 --- a/client/src/Routes/v2router.tsx +++ b/client/src/Routes/v2router.tsx @@ -25,7 +25,11 @@ const V2Routes = ({ mode = "light" }) => { element={} > Uptime} + /> + Test Page} /> diff --git a/client/src/Utils/Theme/v2/palette.ts b/client/src/Utils/Theme/v2/palette.ts index 2e41a159c..855f7b6b8 100644 --- a/client/src/Utils/Theme/v2/palette.ts +++ b/client/src/Utils/Theme/v2/palette.ts @@ -54,6 +54,7 @@ export const lightPalette = { main: colors.offWhite, contrastText: colors.blueGray800, contrastTextSecondary: colors.blueGray600, + contrastTextTertiary: colors.blueGray500, lowContrast: colors.gray250, }, secondary: { @@ -78,6 +79,7 @@ export const darkPalette = { main: colors.offBlack, contrastText: colors.blueGray50, contrastTextSecondary: colors.gray200, + contrastTextTertiary: colors.gray500, lowContrast: colors.blueGray600, }, secondary: { diff --git a/client/src/store.js b/client/src/store.js index 69aa3d50b..565d68519 100644 --- a/client/src/store.js +++ b/client/src/store.js @@ -1,6 +1,7 @@ import { configureStore, combineReducers } from "@reduxjs/toolkit"; import authReducer from "./Features/Auth/authSlice"; +import v2AuthReducer from "./Features/Auth/v2AuthSlice"; import uiReducer from "./Features/UI/uiSlice"; import storage from "redux-persist/lib/storage"; import { persistReducer, persistStore, createTransform } from "redux-persist"; @@ -19,12 +20,13 @@ const authTransform = createTransform( const persistConfig = { key: "root", storage, - whitelist: ["auth", "ui"], + whitelist: ["auth", "v2Auth", "ui"], transforms: [authTransform], }; const rootReducer = combineReducers({ auth: authReducer, + v2Auth: v2AuthReducer, ui: uiReducer, }); diff --git a/client/src/types/mui.d.ts b/client/src/types/mui.d.ts index 5f5c1c38b..84bcd799f 100644 --- a/client/src/types/mui.d.ts +++ b/client/src/types/mui.d.ts @@ -12,6 +12,7 @@ declare module "@mui/material/styles" { interface PaletteColor { contrastTextSecondary?: string; + contrastTextTertiary?: string; lowContrast?: string; } } From 735054b4e15a5fbd024522f56019c4723053631e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 1 Oct 2025 13:57:04 -0700 Subject: [PATCH 9/9] remove unused error --- client/src/Pages/v2/Auth/Login.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Pages/v2/Auth/Login.tsx b/client/src/Pages/v2/Auth/Login.tsx index 2a5629917..a41750c27 100644 --- a/client/src/Pages/v2/Auth/Login.tsx +++ b/client/src/Pages/v2/Auth/Login.tsx @@ -23,7 +23,7 @@ const Login = () => { const { t } = useTranslation(); const dispatch = useDispatch(); const theme = useTheme(); - const { post, loading, error } = usePost("/auth/login"); + const { post, loading } = usePost("/auth/login"); const navigate = useNavigate(); const {